Code refactoring of hawkbit-dmf-amqp (#2054)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -9,7 +9,6 @@
|
|||||||
SPDX-License-Identifier: EPL-2.0
|
SPDX-License-Identifier: EPL-2.0
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0">
|
xmlns="http://maven.apache.org/POM/4.0.0">
|
||||||
@@ -39,17 +38,18 @@
|
|||||||
<artifactId>hawkbit-repository-api</artifactId>
|
<artifactId>hawkbit-repository-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.plugin</groupId>
|
<groupId>org.springframework.plugin</groupId>
|
||||||
<artifactId>spring-plugin-core</artifactId>
|
<artifactId>spring-plugin-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.servlet</groupId>
|
<groupId>jakarta.servlet</groupId>
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
<artifactId>jakarta.servlet-api</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.hawkbit</groupId>
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
|
|||||||
@@ -48,7 +48,5 @@ public class DDIStart {
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
|
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
|
||||||
public static class MethodSecurityConfig {
|
public static class MethodSecurityConfig {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
@@ -30,8 +29,9 @@ public abstract class AbstractSecurityTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
final DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(context)
|
mvc = MockMvcBuilders.webAppContextSetup(context)
|
||||||
.apply(SecurityMockMvcConfigurers.springSecurity()).dispatchOptions(true);
|
.apply(SecurityMockMvcConfigurers.springSecurity())
|
||||||
mvc = builder.build();
|
.dispatchOptions(true)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,8 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
|
||||||
@TestPropertySource(properties = { "hawkbit.server.security.allowedHostNames=localhost",
|
@TestPropertySource(properties = {
|
||||||
|
"hawkbit.server.security.allowedHostNames=localhost",
|
||||||
"hawkbit.server.security.httpFirewallIgnoredPaths=/index.html" })
|
"hawkbit.server.security.httpFirewallIgnoredPaths=/index.html" })
|
||||||
@Feature("Integration Test - Security")
|
@Feature("Integration Test - Security")
|
||||||
@Story("Allowed Host Names")
|
@Story("Allowed Host Names")
|
||||||
@@ -28,13 +29,15 @@ public class AllowedHostNamesTest extends AbstractSecurityTest {
|
|||||||
@Test
|
@Test
|
||||||
@Description("Tests whether a RequestRejectedException is thrown when not allowed host is used")
|
@Description("Tests whether a RequestRejectedException is thrown when not allowed host is used")
|
||||||
public void allowedHostNameWithNotAllowedHost() throws Exception {
|
public void allowedHostNameWithNotAllowedHost() throws Exception {
|
||||||
mvc.perform(get("/").header(HttpHeaders.HOST, "www.google.com")).andExpect(status().isBadRequest());
|
mvc.perform(get("/").header(HttpHeaders.HOST, "www.google.com"))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Tests whether request is redirected when allowed host is used")
|
@Description("Tests whether request is redirected when allowed host is used")
|
||||||
public void allowedHostNameWithAllowedHost() throws Exception {
|
public void allowedHostNameWithAllowedHost() throws Exception {
|
||||||
mvc.perform(get("/").header(HttpHeaders.HOST, "localhost")).andExpect(status().is3xxRedirection());
|
mvc.perform(get("/").header(HttpHeaders.HOST, "localhost"))
|
||||||
|
.andExpect(status().is3xxRedirection());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ public class PreAuthorizeEnabledTest extends AbstractSecurityTest {
|
|||||||
@Description("Tests whether request fail if a role is forbidden for the user")
|
@Description("Tests whether request fail if a role is forbidden for the user")
|
||||||
@WithUser(authorities = { SpPermission.READ_TARGET })
|
@WithUser(authorities = { SpPermission.READ_TARGET })
|
||||||
public void failIfNoRole() throws Exception {
|
public void failIfNoRole() throws Exception {
|
||||||
mvc.perform(get("/DEFAULT/controller/v1/controllerId")).andExpect(result ->
|
mvc.perform(get("/DEFAULT/controller/v1/controllerId"))
|
||||||
|
.andExpect(result ->
|
||||||
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.FORBIDDEN.value()));
|
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.FORBIDDEN.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +39,8 @@ public class PreAuthorizeEnabledTest extends AbstractSecurityTest {
|
|||||||
@Description("Tests whether request succeed if a role is granted for the user")
|
@Description("Tests whether request succeed if a role is granted for the user")
|
||||||
@WithUser(authorities = { SpPermission.SpringEvalExpressions.CONTROLLER_ROLE })
|
@WithUser(authorities = { SpPermission.SpringEvalExpressions.CONTROLLER_ROLE })
|
||||||
public void successIfHasRole() throws Exception {
|
public void successIfHasRole() throws Exception {
|
||||||
mvc.perform(get("/DEFAULT/controller/v1/controllerId")).andExpect(result -> {
|
mvc.perform(get("/DEFAULT/controller/v1/controllerId"))
|
||||||
|
.andExpect(result -> {
|
||||||
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value());
|
assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
SPDX-License-Identifier: EPL-2.0
|
SPDX-License-Identifier: EPL-2.0
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@@ -43,6 +42,7 @@
|
|||||||
<artifactId>hawkbit-dmf-api</artifactId>
|
<artifactId>hawkbit-dmf-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||||
@@ -67,6 +67,7 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-logging</artifactId>
|
<artifactId>spring-boot-starter-logging</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-collections4</artifactId>
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ public abstract class AbstractAmqpErrorHandler<T> implements AmqpErrorHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doHandle(Throwable throwable, AmqpErrorHandlerChain chain) {
|
public void doHandle(Throwable throwable, AmqpErrorHandlerChain chain) {
|
||||||
// retrieving the cause of throwable as it contains the actual class of
|
// retrieving the cause of throwable as it contains the actual class of exception
|
||||||
// exception
|
|
||||||
final Throwable cause = throwable.getCause();
|
final Throwable cause = throwable.getCause();
|
||||||
if (getExceptionClass().isAssignableFrom(cause.getClass())) {
|
if (getExceptionClass().isAssignableFrom(cause.getClass())) {
|
||||||
throw new AmqpRejectAndDontRequeueException(getErrorMessage(throwable));
|
throw new AmqpRejectAndDontRequeueException(getErrorMessage(throwable));
|
||||||
@@ -43,5 +42,4 @@ public abstract class AbstractAmqpErrorHandler<T> implements AmqpErrorHandler {
|
|||||||
public String getErrorMessage(Throwable throwable) {
|
public String getErrorMessage(Throwable throwable) {
|
||||||
return AmqpErrorMessageComposer.constructErrorMessage(throwable);
|
return AmqpErrorMessageComposer.constructErrorMessage(throwable);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -127,8 +127,7 @@ public class AmqpConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@link RabbitTemplate} with automatic retry, published confirms and
|
* @return {@link RabbitTemplate} with automatic retry, published confirms and {@link Jackson2JsonMessageConverter}.
|
||||||
* {@link Jackson2JsonMessageConverter}.
|
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public RabbitTemplate rabbitTemplate() {
|
public RabbitTemplate rabbitTemplate() {
|
||||||
@@ -246,7 +245,8 @@ public class AmqpConfiguration {
|
|||||||
final SystemSecurityContext systemSecurityContext,
|
final SystemSecurityContext systemSecurityContext,
|
||||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||||
final ConfirmationManagement confirmationManagement) {
|
final ConfirmationManagement confirmationManagement) {
|
||||||
return new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherService, controllerManagement,
|
return new AmqpMessageHandlerService(
|
||||||
|
rabbitTemplate, amqpMessageDispatcherService, controllerManagement,
|
||||||
entityFactory, systemSecurityContext, tenantConfigurationManagement, confirmationManagement);
|
entityFactory, systemSecurityContext, tenantConfigurationManagement, confirmationManagement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +279,8 @@ public class AmqpConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(AmqpMessageDispatcherService.class)
|
@ConditionalOnMissingBean(AmqpMessageDispatcherService.class)
|
||||||
AmqpMessageDispatcherService amqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
|
AmqpMessageDispatcherService amqpMessageDispatcherService(
|
||||||
|
final RabbitTemplate rabbitTemplate,
|
||||||
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
|
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
|
||||||
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
|
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
|
||||||
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement,
|
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement,
|
||||||
|
|||||||
@@ -28,15 +28,14 @@ public class AmqpDeadletterProperties {
|
|||||||
private static final int THREE_WEEKS = 21;
|
private static final int THREE_WEEKS = 21;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message time to live (ttl) for the deadletter queue. Default ttl is 3
|
* Message time to live (ttl) for the dead letter queue. Default ttl is 3 weeks.
|
||||||
* weeks.
|
|
||||||
*/
|
*/
|
||||||
private long ttl = Duration.ofDays(THREE_WEEKS).toMillis();
|
private long ttl = Duration.ofDays(THREE_WEEKS).toMillis();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the deadletter arguments.
|
* Return the dead letter arguments.
|
||||||
*
|
*
|
||||||
* @param exchange the deadletter exchange
|
* @param exchange the dead letter exchange
|
||||||
* @return map which holds the properties
|
* @return map which holds the properties
|
||||||
*/
|
*/
|
||||||
public Map<String, Object> getDeadLetterExchangeArgs(final String exchange) {
|
public Map<String, Object> getDeadLetterExchangeArgs(final String exchange) {
|
||||||
@@ -46,10 +45,10 @@ public class AmqpDeadletterProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a deadletter queue with ttl for messages
|
* Create a dead letter queue with ttl for messages
|
||||||
*
|
*
|
||||||
* @param queueName the deadletter queue name
|
* @param queueName the dead letter queue name
|
||||||
* @return the deadletter queue
|
* @return the dead letter queue
|
||||||
*/
|
*/
|
||||||
public Queue createDeadletterQueue(final String queueName) {
|
public Queue createDeadletterQueue(final String queueName) {
|
||||||
return new Queue(queueName, true, false, false, getTTLArgs());
|
return new Queue(queueName, true, false, false, getTTLArgs());
|
||||||
|
|||||||
@@ -10,8 +10,7 @@
|
|||||||
package org.eclipse.hawkbit.amqp;
|
package org.eclipse.hawkbit.amqp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface declaration of {@link AmqpErrorHandler} that handles errors based on the
|
* Interface declaration of {@link AmqpErrorHandler} that handles errors based on the types of exception.
|
||||||
* types of exception.
|
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface AmqpErrorHandler {
|
public interface AmqpErrorHandler {
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ public final class AmqpErrorMessageComposer {
|
|||||||
* @return meaningful error message
|
* @return meaningful error message
|
||||||
*/
|
*/
|
||||||
public static String constructErrorMessage(final Throwable throwable) {
|
public static String constructErrorMessage(final Throwable throwable) {
|
||||||
StringBuilder completeErrorMessage = new StringBuilder();
|
|
||||||
final String mainErrorMsg = throwable.getCause().getMessage();
|
final String mainErrorMsg = throwable.getCause().getMessage();
|
||||||
|
|
||||||
if (throwable instanceof ListenerExecutionFailedException) {
|
if (throwable instanceof ListenerExecutionFailedException) {
|
||||||
Collection<Message> failedMessages = ((ListenerExecutionFailedException) throwable).getFailedMessages();
|
Collection<Message> failedMessages = ((ListenerExecutionFailedException) throwable).getFailedMessages();
|
||||||
// since the intended message content is always on top of the collection, we only extract the first one
|
// since the intended message content is always on top of the collection, we only extract the first one
|
||||||
@@ -41,11 +39,10 @@ public final class AmqpErrorMessageComposer {
|
|||||||
final byte[] amqpFailedMsgBody = failedMessage.getBody();
|
final byte[] amqpFailedMsgBody = failedMessage.getBody();
|
||||||
final Map<String, Object> amqpFailedMsgHeaders = failedMessage.getMessageProperties().getHeaders();
|
final Map<String, Object> amqpFailedMsgHeaders = failedMessage.getMessageProperties().getHeaders();
|
||||||
|
|
||||||
String amqpFailedMsgConcatenatedHeaders = amqpFailedMsgHeaders.keySet().stream()
|
final String amqpFailedMsgConcatenatedHeaders = amqpFailedMsgHeaders.keySet().stream()
|
||||||
.map(key -> key + "=" + amqpFailedMsgHeaders.get(key)).collect(Collectors.joining(", ", "{", "}"));
|
.map(key -> key + "=" + amqpFailedMsgHeaders.get(key))
|
||||||
completeErrorMessage.append(mainErrorMsg).append(new String(amqpFailedMsgBody))
|
.collect(Collectors.joining(", ", "{", "}"));
|
||||||
.append(amqpFailedMsgConcatenatedHeaders);
|
return mainErrorMsg + new String(amqpFailedMsgBody) + amqpFailedMsgConcatenatedHeaders;
|
||||||
return completeErrorMessage.toString();
|
|
||||||
}
|
}
|
||||||
return mainErrorMsg;
|
return mainErrorMsg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,8 +84,7 @@ import org.springframework.util.CollectionUtils;
|
|||||||
* {@link AmqpMessageDispatcherService} create all outgoing AMQP messages and
|
* {@link AmqpMessageDispatcherService} create all outgoing AMQP messages and
|
||||||
* delegate the messages to a {@link AmqpMessageSenderService}.
|
* delegate the messages to a {@link AmqpMessageSenderService}.
|
||||||
*
|
*
|
||||||
* Additionally the dispatcher listener/subscribe for some target events e.g.
|
* Additionally, the dispatcher listener/subscribe for some target events e.g. assignment.
|
||||||
* assignment.
|
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AmqpMessageDispatcherService extends BaseAmqpService {
|
public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||||
@@ -112,12 +111,12 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
* @param systemSecurityContext for execution with system permissions
|
* @param systemSecurityContext for execution with system permissions
|
||||||
* @param systemManagement the systemManagement
|
* @param systemManagement the systemManagement
|
||||||
* @param targetManagement to access target information
|
* @param targetManagement to access target information
|
||||||
* @param serviceMatcher to check in cluster case if the message is from the same
|
* @param serviceMatcher to check in cluster case if the message is from the same cluster node
|
||||||
* cluster node
|
|
||||||
* @param distributionSetManagement to retrieve modules
|
* @param distributionSetManagement to retrieve modules
|
||||||
* @param tenantConfigurationManagement to access tenant configuration
|
* @param tenantConfigurationManagement to access tenant configuration
|
||||||
*/
|
*/
|
||||||
protected AmqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
|
protected AmqpMessageDispatcherService(
|
||||||
|
final RabbitTemplate rabbitTemplate,
|
||||||
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
|
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
|
||||||
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
|
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
|
||||||
final TargetManagement targetManagement, final ServiceMatcher serviceMatcher,
|
final TargetManagement targetManagement, final ServiceMatcher serviceMatcher,
|
||||||
@@ -138,15 +137,15 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBatchAssignmentsEnabled() {
|
public boolean isBatchAssignmentsEnabled() {
|
||||||
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
|
return systemSecurityContext.runAsSystem(() ->
|
||||||
|
tenantConfigurationManagement
|
||||||
.getConfigurationValue(BATCH_ASSIGNMENTS_ENABLED, Boolean.class).getValue());
|
.getConfigurationValue(BATCH_ASSIGNMENTS_ENABLED, Boolean.class).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to send a message to a RabbitMQ Exchange after the Distribution
|
* Method to send a message to a RabbitMQ Exchange after the Distribution set has been assign to a Target.
|
||||||
* set has been assign to a Target.
|
|
||||||
*
|
*
|
||||||
* @param assignedEvent the object to be send.
|
* @param assignedEvent the object to be sent.
|
||||||
*/
|
*/
|
||||||
@EventListener(classes = TargetAssignDistributionSetEvent.class)
|
@EventListener(classes = TargetAssignDistributionSetEvent.class)
|
||||||
protected void targetAssignDistributionSet(final TargetAssignDistributionSetEvent assignedEvent) {
|
protected void targetAssignDistributionSet(final TargetAssignDistributionSetEvent assignedEvent) {
|
||||||
@@ -154,13 +153,11 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Target> filteredTargetList = getTargetsWithoutPendingCancellations(
|
final List<Target> filteredTargetList = getTargetsWithoutPendingCancellations(assignedEvent.getActions().keySet());
|
||||||
assignedEvent.getActions().keySet());
|
|
||||||
|
|
||||||
if (!filteredTargetList.isEmpty()) {
|
if (!filteredTargetList.isEmpty()) {
|
||||||
log.debug("targetAssignDistributionSet retrieved. I will forward it to DMF broker.");
|
log.debug("targetAssignDistributionSet retrieved. I will forward it to DMF broker.");
|
||||||
sendUpdateMessageToTargets(assignedEvent.getDistributionSetId(), assignedEvent.getActions(),
|
sendUpdateMessageToTargets(assignedEvent.getDistributionSetId(), assignedEvent.getActions(), filteredTargetList);
|
||||||
filteredTargetList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,16 +175,17 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
sendMultiActionRequestMessages(multiActionEvent.getTenant(), multiActionEvent.getControllerIds());
|
sendMultiActionRequestMessages(multiActionEvent.getTenant(), multiActionEvent.getControllerIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendUpdateMessageToTarget(final ActionProperties actionsProps, final Target target,
|
protected void sendUpdateMessageToTarget(
|
||||||
|
final ActionProperties actionsProps, final Target target,
|
||||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||||
final Map<String, ActionProperties> actionProp = new HashMap<>();
|
final Map<String, ActionProperties> actionProp = new HashMap<>();
|
||||||
actionProp.put(target.getControllerId(), actionsProps);
|
actionProp.put(target.getControllerId(), actionsProps);
|
||||||
sendUpdateMessageToTargets(actionProp, Collections.singletonList(target), softwareModules);
|
sendUpdateMessageToTargets(actionProp, Collections.singletonList(target), softwareModules);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendMultiActionRequestToTarget(final String tenant, final Target target, final List<Action> actions,
|
protected void sendMultiActionRequestToTarget(
|
||||||
|
final String tenant, final Target target, final List<Action> actions,
|
||||||
final Function<Action, Map<SoftwareModule, List<SoftwareModuleMetadata>>> getSoftwareModuleMetaData) {
|
final Function<Action, Map<SoftwareModule, List<SoftwareModuleMetadata>>> getSoftwareModuleMetaData) {
|
||||||
|
|
||||||
final URI targetAddress = target.getAddress();
|
final URI targetAddress = target.getAddress();
|
||||||
if (!IpUtil.isAmqpUri(targetAddress) || CollectionUtils.isEmpty(actions)) {
|
if (!IpUtil.isAmqpUri(targetAddress) || CollectionUtils.isEmpty(actions)) {
|
||||||
return;
|
return;
|
||||||
@@ -195,26 +193,26 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
|
|
||||||
final DmfMultiActionRequest multiActionRequest = new DmfMultiActionRequest();
|
final DmfMultiActionRequest multiActionRequest = new DmfMultiActionRequest();
|
||||||
actions.forEach(action -> {
|
actions.forEach(action -> {
|
||||||
final DmfActionRequest actionRequest = createDmfActionRequest(target, action,
|
final DmfActionRequest actionRequest = createDmfActionRequest(target, action, getSoftwareModuleMetaData.apply(action));
|
||||||
getSoftwareModuleMetaData.apply(action));
|
|
||||||
final int weight = deploymentManagement.getWeightConsideringDefault(action);
|
final int weight = deploymentManagement.getWeightConsideringDefault(action);
|
||||||
multiActionRequest.addElement(getEventTypeForAction(action), actionRequest, weight);
|
multiActionRequest.addElement(getEventTypeForAction(action), actionRequest, weight);
|
||||||
});
|
});
|
||||||
|
|
||||||
final Message message = getMessageConverter().toMessage(multiActionRequest,
|
final Message message = getMessageConverter().toMessage(
|
||||||
|
multiActionRequest,
|
||||||
createConnectorMessagePropertiesEvent(tenant, target.getControllerId(), EventTopic.MULTI_ACTION));
|
createConnectorMessagePropertiesEvent(tenant, target.getControllerId(), EventTopic.MULTI_ACTION));
|
||||||
amqpSenderService.sendMessage(message, targetAddress);
|
amqpSenderService.sendMessage(message, targetAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DmfDownloadAndUpdateRequest createDownloadAndUpdateRequest(final Target target, final Long actionId,
|
protected DmfDownloadAndUpdateRequest createDownloadAndUpdateRequest(
|
||||||
|
final Target target, final Long actionId,
|
||||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||||
final DmfDownloadAndUpdateRequest request = new DmfDownloadAndUpdateRequest();
|
final DmfDownloadAndUpdateRequest request = new DmfDownloadAndUpdateRequest();
|
||||||
request.setActionId(actionId);
|
request.setActionId(actionId);
|
||||||
request.setTargetSecurityToken(systemSecurityContext.runAsSystem(target::getSecurityToken));
|
request.setTargetSecurityToken(systemSecurityContext.runAsSystem(target::getSecurityToken));
|
||||||
|
|
||||||
if (softwareModules != null) {
|
if (softwareModules != null) {
|
||||||
softwareModules.entrySet()
|
softwareModules.entrySet().forEach(entry -> request.addSoftwareModule(convertToAmqpSoftwareModule(target, entry)));
|
||||||
.forEach(entry -> request.addSoftwareModule(convertToAmqpSoftwareModule(target, entry)));
|
|
||||||
}
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
@@ -231,24 +229,22 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Target> eventTargets = partitionedParallelExecution(cancelEvent.getActions().keySet(),
|
final List<Target> eventTargets = partitionedParallelExecution(
|
||||||
targetManagement::getByControllerID);
|
cancelEvent.getActions().keySet(), targetManagement::getByControllerID);
|
||||||
|
|
||||||
eventTargets.forEach(target -> {
|
eventTargets.forEach(target ->
|
||||||
cancelEvent.getActionPropertiesForController(target.getControllerId()).map(ActionProperties::getId)
|
cancelEvent.getActionPropertiesForController(target.getControllerId())
|
||||||
.ifPresent(actionId -> {
|
.map(ActionProperties::getId)
|
||||||
sendCancelMessageToTarget(cancelEvent.getTenant(), target.getControllerId(), actionId,
|
.ifPresent(actionId ->
|
||||||
target.getAddress());
|
sendCancelMessageToTarget(cancelEvent.getTenant(), target.getControllerId(), actionId, target.getAddress())
|
||||||
});
|
)
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to send a message to a RabbitMQ Exchange after a Target was
|
* Method to send a message to a RabbitMQ Exchange after a Target was deleted.
|
||||||
* deleted.
|
|
||||||
*
|
*
|
||||||
* @param deleteEvent the TargetDeletedEvent which holds the necessary data for
|
* @param deleteEvent the TargetDeletedEvent which holds the necessary data for sending a target delete message.
|
||||||
* sending a target delete message.
|
|
||||||
*/
|
*/
|
||||||
@EventListener(classes = TargetDeletedEvent.class)
|
@EventListener(classes = TargetDeletedEvent.class)
|
||||||
protected void targetDelete(final TargetDeletedEvent deleteEvent) {
|
protected void targetDelete(final TargetDeletedEvent deleteEvent) {
|
||||||
@@ -260,15 +256,18 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
|
|
||||||
@EventListener(classes = TargetAttributesRequestedEvent.class)
|
@EventListener(classes = TargetAttributesRequestedEvent.class)
|
||||||
protected void targetTriggerUpdateAttributes(final TargetAttributesRequestedEvent updateAttributesEvent) {
|
protected void targetTriggerUpdateAttributes(final TargetAttributesRequestedEvent updateAttributesEvent) {
|
||||||
sendUpdateAttributesMessageToTarget(updateAttributesEvent.getTenant(), updateAttributesEvent.getControllerId(),
|
sendUpdateAttributesMessageToTarget(
|
||||||
|
updateAttributesEvent.getTenant(), updateAttributesEvent.getControllerId(),
|
||||||
updateAttributesEvent.getTargetAddress());
|
updateAttributesEvent.getTargetAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendPingReponseToDmfReceiver(final Message ping, final String tenant, final String virtualHost) {
|
protected void sendPingResponseToDmfReceiver(final Message ping, final String tenant, final String virtualHost) {
|
||||||
final Message message = MessageBuilder.withBody(String.valueOf(System.currentTimeMillis()).getBytes())
|
final Message message = MessageBuilder
|
||||||
|
.withBody(String.valueOf(System.currentTimeMillis()).getBytes())
|
||||||
.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
|
.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
|
||||||
.setCorrelationId(ping.getMessageProperties().getCorrelationId())
|
.setCorrelationId(ping.getMessageProperties().getCorrelationId())
|
||||||
.setHeader(MessageHeaderKey.TYPE, MessageType.PING_RESPONSE).setHeader(MessageHeaderKey.TENANT, tenant)
|
.setHeader(MessageHeaderKey.TYPE, MessageType.PING_RESPONSE)
|
||||||
|
.setHeader(MessageHeaderKey.TENANT, tenant)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
amqpSenderService.sendMessage(message,
|
amqpSenderService.sendMessage(message,
|
||||||
@@ -279,8 +278,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return isFromSelf(event);
|
return isFromSelf(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendCancelMessageToTarget(final String tenant, final String controllerId, final Long actionId,
|
protected void sendCancelMessageToTarget(final String tenant, final String controllerId, final Long actionId, final URI address) {
|
||||||
final URI address) {
|
|
||||||
if (!IpUtil.isAmqpUri(address)) {
|
if (!IpUtil.isAmqpUri(address)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -288,11 +286,11 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
final DmfActionRequest actionRequest = new DmfActionRequest();
|
final DmfActionRequest actionRequest = new DmfActionRequest();
|
||||||
actionRequest.setActionId(actionId);
|
actionRequest.setActionId(actionId);
|
||||||
|
|
||||||
final Message message = getMessageConverter().toMessage(actionRequest,
|
final Message message = getMessageConverter().toMessage(
|
||||||
|
actionRequest,
|
||||||
createConnectorMessagePropertiesEvent(tenant, controllerId, EventTopic.CANCEL_DOWNLOAD));
|
createConnectorMessagePropertiesEvent(tenant, controllerId, EventTopic.CANCEL_DOWNLOAD));
|
||||||
|
|
||||||
amqpSenderService.sendMessage(message, address);
|
amqpSenderService.sendMessage(message, address);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DmfTarget convertToDmfTarget(final Target target, final Long actionId) {
|
protected DmfTarget convertToDmfTarget(final Target target, final Long actionId) {
|
||||||
@@ -309,18 +307,18 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
* @param target the target
|
* @param target the target
|
||||||
* @param actionId the actionId
|
* @param actionId the actionId
|
||||||
* @param softwareModules the software modules
|
* @param softwareModules the software modules
|
||||||
* @return
|
* @return confirm request
|
||||||
*/
|
*/
|
||||||
protected DmfConfirmRequest createConfirmRequest(final Target target, final Long actionId, final Map<SoftwareModule,
|
protected DmfConfirmRequest createConfirmRequest(
|
||||||
List<SoftwareModuleMetadata>> softwareModules) {
|
final Target target, final Long actionId, final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||||
final DmfConfirmRequest request = new DmfConfirmRequest();
|
final DmfConfirmRequest request = new DmfConfirmRequest();
|
||||||
request.setActionId(actionId);
|
request.setActionId(actionId);
|
||||||
request.setTargetSecurityToken(systemSecurityContext.runAsSystem(target::getSecurityToken));
|
request.setTargetSecurityToken(systemSecurityContext.runAsSystem(target::getSecurityToken));
|
||||||
|
|
||||||
//Software modules can be filtered in the future exposing only the needed.
|
//Software modules can be filtered in the future exposing only the needed.
|
||||||
if (softwareModules != null) {
|
if (softwareModules != null) {
|
||||||
softwareModules.entrySet()
|
softwareModules.entrySet().forEach(entry ->
|
||||||
.forEach(entry -> request.addSoftwareModule(convertToAmqpSoftwareModule(target, entry)));
|
request.addSoftwareModule(convertToAmqpSoftwareModule(target, entry)));
|
||||||
}
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
@@ -332,12 +330,9 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to get the type of event depending on whether the action is a
|
* Method to get the type of event depending on whether the action is a DOWNLOAD_ONLY action or if it has a valid maintenance window
|
||||||
* DOWNLOAD_ONLY action or if it has a valid maintenance window available or
|
* available or not based on defined maintenance schedule. In case of no maintenance schedule or if there is a valid window available,
|
||||||
* not based on defined maintenance schedule. In case of no maintenance
|
* the topic {@link EventTopic#DOWNLOAD_AND_INSTALL} is returned else {@link EventTopic#DOWNLOAD} is returned.
|
||||||
* schedule or if there is a valid window available, the topic
|
|
||||||
* {@link EventTopic#DOWNLOAD_AND_INSTALL} is returned else
|
|
||||||
* {@link EventTopic#DOWNLOAD} is returned.
|
|
||||||
*
|
*
|
||||||
* @param action current action properties.
|
* @param action current action properties.
|
||||||
* @return {@link EventTopic} to use for message.
|
* @return {@link EventTopic} to use for message.
|
||||||
@@ -352,8 +347,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the {@link EventTopic} for the given {@link Action}, depending
|
* Determines the {@link EventTopic} for the given {@link Action}, depending on its action type.
|
||||||
* on its action type.
|
|
||||||
*
|
*
|
||||||
* @param action to obtain the corresponding {@link EventTopic} for
|
* @param action to obtain the corresponding {@link EventTopic} for
|
||||||
* @return the {@link EventTopic} for this action
|
* @return the {@link EventTopic} for this action
|
||||||
@@ -365,8 +359,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return getEventTypeForTarget(new ActionProperties(action));
|
return getEventTypeForTarget(new ActionProperties(action));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T, R> List<R> partitionedParallelExecution(final Collection<T> controllerIds,
|
private static <T, R> List<R> partitionedParallelExecution(
|
||||||
final Function<Collection<T>, List<R>> loadingFunction) {
|
final Collection<T> controllerIds, final Function<Collection<T>, List<R>> loadingFunction) {
|
||||||
// Ensure not exceeding the max value of MAX_PROCESSING_SIZE
|
// Ensure not exceeding the max value of MAX_PROCESSING_SIZE
|
||||||
if (controllerIds.size() > MAX_PROCESSING_SIZE) {
|
if (controllerIds.size() > MAX_PROCESSING_SIZE) {
|
||||||
// Split the provided collection
|
// Split the provided collection
|
||||||
@@ -392,16 +386,16 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MessageProperties createConnectorMessagePropertiesEvent(final String tenant,
|
private static MessageProperties createConnectorMessagePropertiesEvent(
|
||||||
final String controllerId, final EventTopic topic) {
|
final String tenant, final String controllerId, final EventTopic topic) {
|
||||||
final MessageProperties messageProperties = createConnectorMessageProperties(tenant, controllerId);
|
final MessageProperties messageProperties = createConnectorMessageProperties(tenant, controllerId);
|
||||||
messageProperties.setHeader(MessageHeaderKey.TOPIC, topic);
|
messageProperties.setHeader(MessageHeaderKey.TOPIC, topic);
|
||||||
messageProperties.setHeader(MessageHeaderKey.TYPE, MessageType.EVENT);
|
messageProperties.setHeader(MessageHeaderKey.TYPE, MessageType.EVENT);
|
||||||
return messageProperties;
|
return messageProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MessageProperties createConnectorMessagePropertiesDeleteThing(final String tenant,
|
private static MessageProperties createConnectorMessagePropertiesDeleteThing(
|
||||||
final String controllerId) {
|
final String tenant, final String controllerId) {
|
||||||
final MessageProperties messageProperties = createConnectorMessageProperties(tenant, controllerId);
|
final MessageProperties messageProperties = createConnectorMessageProperties(tenant, controllerId);
|
||||||
messageProperties.setHeader(MessageHeaderKey.TYPE, MessageType.THING_DELETED);
|
messageProperties.setHeader(MessageHeaderKey.TYPE, MessageType.THING_DELETED);
|
||||||
return messageProperties;
|
return messageProperties;
|
||||||
@@ -434,30 +428,28 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Target> getTargetsWithoutPendingCancellations(final Set<String> controllerIds) {
|
private List<Target> getTargetsWithoutPendingCancellations(final Set<String> controllerIds) {
|
||||||
return partitionedParallelExecution(controllerIds, partition -> {
|
return partitionedParallelExecution(controllerIds, partition ->
|
||||||
return targetManagement.getByControllerID(partition).stream().filter(target -> {
|
targetManagement.getByControllerID(partition).stream()
|
||||||
|
.filter(target -> {
|
||||||
if (hasPendingCancellations(target.getId())) {
|
if (hasPendingCancellations(target.getId())) {
|
||||||
log.debug("Target {} has pending cancellations. Will not send update message to it.",
|
log.debug("Target {} has pending cancellations. Will not send update message to it.", target.getControllerId());
|
||||||
target.getControllerId());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList()));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUpdateMessageToTargets(final Long dsId, final Map<String, ActionProperties> actionsPropsByTargetId,
|
private void sendUpdateMessageToTargets(
|
||||||
final List<Target> targets) {
|
final Long dsId, final Map<String, ActionProperties> actionsPropsByTargetId, final List<Target> targets) {
|
||||||
distributionSetManagement.get(dsId).ifPresent(ds -> {
|
distributionSetManagement.get(dsId).ifPresent(ds -> {
|
||||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules = getSoftwareModulesWithMetadata(
|
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules = getSoftwareModulesWithMetadata(ds);
|
||||||
ds);
|
|
||||||
sendUpdateMessageToTargets(actionsPropsByTargetId, targets, softwareModules);
|
sendUpdateMessageToTargets(actionsPropsByTargetId, targets, softwareModules);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUpdateMessageToTargets(final Map<String, ActionProperties> actionsPropsByTargetId,
|
private void sendUpdateMessageToTargets(
|
||||||
|
final Map<String, ActionProperties> actionsPropsByTargetId,
|
||||||
final List<Target> targets, final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
final List<Target> targets, final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||||
|
|
||||||
if (!targets.isEmpty() && isBatchAssignmentsEnabled()) {
|
if (!targets.isEmpty() && isBatchAssignmentsEnabled()) {
|
||||||
sendBatchUpdateMessage(actionsPropsByTargetId, targets, softwareModules);
|
sendBatchUpdateMessage(actionsPropsByTargetId, targets, softwareModules);
|
||||||
} else {
|
} else {
|
||||||
@@ -469,16 +461,15 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendMultiActionRequestMessages(final String tenant, final List<String> controllerIds) {
|
private void sendMultiActionRequestMessages(final String tenant, final List<String> controllerIds) {
|
||||||
|
|
||||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModuleMetadata = new HashMap<>();
|
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModuleMetadata = new HashMap<>();
|
||||||
targetManagement.getByControllerID(controllerIds).stream()
|
targetManagement.getByControllerID(controllerIds).stream()
|
||||||
.filter(target -> IpUtil.isAmqpUri(target.getAddress())).forEach(target -> {
|
.filter(target -> IpUtil.isAmqpUri(target.getAddress())).forEach(target -> {
|
||||||
|
|
||||||
final List<Action> activeActions = deploymentManagement
|
final List<Action> activeActions = deploymentManagement
|
||||||
.findActiveActionsWithHighestWeight(target.getControllerId(), MAX_ACTION_COUNT);
|
.findActiveActionsWithHighestWeight(target.getControllerId(), MAX_ACTION_COUNT);
|
||||||
|
|
||||||
activeActions.forEach(action -> action.getDistributionSet().getModules().forEach(
|
activeActions.forEach(action ->
|
||||||
module -> softwareModuleMetadata.computeIfAbsent(module, this::getSoftwareModuleMetadata)));
|
action.getDistributionSet().getModules().forEach(module ->
|
||||||
|
softwareModuleMetadata.computeIfAbsent(module, this::getSoftwareModuleMetadata)));
|
||||||
|
|
||||||
if (!activeActions.isEmpty()) {
|
if (!activeActions.isEmpty()) {
|
||||||
sendMultiActionRequestToTarget(tenant, target, activeActions,
|
sendMultiActionRequestToTarget(tenant, target, activeActions,
|
||||||
@@ -486,10 +477,10 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
.collect(Collectors.toMap(m -> m, softwareModuleMetadata::get)));
|
.collect(Collectors.toMap(m -> m, softwareModuleMetadata::get)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DmfActionRequest createDmfActionRequest(final Target target, final Action action,
|
private DmfActionRequest createDmfActionRequest(
|
||||||
|
final Target target, final Action action,
|
||||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
final Map<SoftwareModule, List<SoftwareModuleMetadata>> softwareModules) {
|
||||||
if (action.isCancelingOrCanceled()) {
|
if (action.isCancelingOrCanceled()) {
|
||||||
return createPlainActionRequest(action);
|
return createPlainActionRequest(action);
|
||||||
@@ -499,9 +490,9 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return createDownloadAndUpdateRequest(target, action.getId(), softwareModules);
|
return createDownloadAndUpdateRequest(target, action.getId(), softwareModules);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendSingleUpdateMessage(final ActionProperties action, final Target target,
|
private void sendSingleUpdateMessage(
|
||||||
|
final ActionProperties action, final Target target,
|
||||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
|
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
|
||||||
|
|
||||||
final String tenant = action.getTenant();
|
final String tenant = action.getTenant();
|
||||||
|
|
||||||
final URI targetAddress = target.getAddress();
|
final URI targetAddress = target.getAddress();
|
||||||
@@ -518,7 +509,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
request = createDownloadAndUpdateRequest(target, action.getId(), modules);
|
request = createDownloadAndUpdateRequest(target, action.getId(), modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Message message = getMessageConverter().toMessage(request,
|
final Message message = getMessageConverter().toMessage(
|
||||||
|
request,
|
||||||
createConnectorMessagePropertiesEvent(tenant, target.getControllerId(), getEventTypeForTarget(action)));
|
createConnectorMessagePropertiesEvent(tenant, target.getControllerId(), getEventTypeForTarget(action)));
|
||||||
amqpSenderService.sendMessage(message, targetAddress);
|
amqpSenderService.sendMessage(message, targetAddress);
|
||||||
}
|
}
|
||||||
@@ -528,8 +520,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Message message = new Message("".getBytes(),
|
final Message message = new Message("".getBytes(), createConnectorMessagePropertiesDeleteThing(tenant, controllerId));
|
||||||
createConnectorMessagePropertiesDeleteThing(tenant, controllerId));
|
|
||||||
amqpSenderService.sendMessage(message, URI.create(targetAddress));
|
amqpSenderService.sendMessage(message, URI.create(targetAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,19 +536,20 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return deploymentManagement.hasPendingCancellations(targetId);
|
return deploymentManagement.hasPendingCancellations(targetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUpdateAttributesMessageToTarget(final String tenant, final String controllerId,
|
private void sendUpdateAttributesMessageToTarget(final String tenant, final String controllerId, final String targetAddress) {
|
||||||
final String targetAddress) {
|
|
||||||
if (!hasValidAddress(targetAddress)) {
|
if (!hasValidAddress(targetAddress)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Message message = new Message("".getBytes(),
|
final Message message = new Message(
|
||||||
|
"".getBytes(),
|
||||||
createConnectorMessagePropertiesEvent(tenant, controllerId, EventTopic.REQUEST_ATTRIBUTES_UPDATE));
|
createConnectorMessagePropertiesEvent(tenant, controllerId, EventTopic.REQUEST_ATTRIBUTES_UPDATE));
|
||||||
|
|
||||||
amqpSenderService.sendMessage(message, URI.create(targetAddress));
|
amqpSenderService.sendMessage(message, URI.create(targetAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
private DmfSoftwareModule convertToAmqpSoftwareModule(final Target target,
|
private DmfSoftwareModule convertToAmqpSoftwareModule(
|
||||||
|
final Target target,
|
||||||
final Entry<SoftwareModule, List<SoftwareModuleMetadata>> entry) {
|
final Entry<SoftwareModule, List<SoftwareModuleMetadata>> entry) {
|
||||||
final DmfSoftwareModule amqpSoftwareModule = new DmfSoftwareModule();
|
final DmfSoftwareModule amqpSoftwareModule = new DmfSoftwareModule();
|
||||||
amqpSoftwareModule.setModuleId(entry.getKey().getId());
|
amqpSoftwareModule.setModuleId(entry.getKey().getId());
|
||||||
@@ -596,7 +588,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
new SoftwareData(localArtifact.getSoftwareModule().getId(), localArtifact.getFilename(),
|
new SoftwareData(localArtifact.getSoftwareModule().getId(), localArtifact.getFilename(),
|
||||||
localArtifact.getId(), localArtifact.getSha1Hash())),
|
localArtifact.getId(), localArtifact.getSha1Hash())),
|
||||||
ApiType.DMF)
|
ApiType.DMF)
|
||||||
.stream().collect(Collectors.toMap(ArtifactUrl::getProtocol, ArtifactUrl::getRef)));
|
.stream()
|
||||||
|
.collect(Collectors.toMap(ArtifactUrl::getProtocol, ArtifactUrl::getRef)));
|
||||||
|
|
||||||
artifact.setFilename(localArtifact.getFilename());
|
artifact.setFilename(localArtifact.getFilename());
|
||||||
artifact.setHashes(new DmfArtifactHash(localArtifact.getSha1Hash(), localArtifact.getMd5Hash()));
|
artifact.setHashes(new DmfArtifactHash(localArtifact.getSha1Hash(), localArtifact.getMd5Hash()));
|
||||||
@@ -605,8 +598,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return artifact;
|
return artifact;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<SoftwareModule, List<SoftwareModuleMetadata>> getSoftwareModulesWithMetadata(
|
private Map<SoftwareModule, List<SoftwareModuleMetadata>> getSoftwareModulesWithMetadata(final DistributionSet distributionSet) {
|
||||||
final DistributionSet distributionSet) {
|
|
||||||
return distributionSet.getModules().stream().collect(Collectors.toMap(m -> m, this::getSoftwareModuleMetadata));
|
return distributionSet.getModules().stream().collect(Collectors.toMap(m -> m, this::getSoftwareModuleMetadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,11 +607,14 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), module.getId()).getContent();
|
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), module.getId()).getContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendBatchUpdateMessage(final Map<String, ActionProperties> actions, final List<Target> targets,
|
private void sendBatchUpdateMessage(
|
||||||
|
final Map<String, ActionProperties> actions, final List<Target> targets,
|
||||||
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
|
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
|
||||||
|
|
||||||
final List<DmfTarget> dmfTargets = targets.stream().filter(target -> IpUtil.isAmqpUri(target.getAddress()))
|
final List<DmfTarget> dmfTargets = targets.stream()
|
||||||
.map(t -> convertToDmfTarget(t, actions.get(t.getControllerId()).getId())).collect(Collectors.toList());
|
.filter(target -> IpUtil.isAmqpUri(target.getAddress()))
|
||||||
|
.map(t -> convertToDmfTarget(t, actions.get(t.getControllerId()).getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
final DmfBatchDownloadAndUpdateRequest batchRequest = new DmfBatchDownloadAndUpdateRequest();
|
final DmfBatchDownloadAndUpdateRequest batchRequest = new DmfBatchDownloadAndUpdateRequest();
|
||||||
batchRequest.setTimestamp(System.currentTimeMillis());
|
batchRequest.setTimestamp(System.currentTimeMillis());
|
||||||
@@ -630,15 +625,15 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
// target-specific urls
|
// target-specific urls
|
||||||
final Target firstTarget = targets.get(0);
|
final Target firstTarget = targets.get(0);
|
||||||
if (modules != null) {
|
if (modules != null) {
|
||||||
modules.entrySet()
|
modules.entrySet().forEach(entry ->
|
||||||
.forEach(entry -> batchRequest.addSoftwareModule(convertToAmqpSoftwareModule(firstTarget, entry)));
|
batchRequest.addSoftwareModule(convertToAmqpSoftwareModule(firstTarget, entry)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use only the first action when constructing message as Tenant and
|
// we use only the first action when constructing message as Tenant and action type are the same
|
||||||
// action type are the same
|
|
||||||
// since all actions have the same trigger
|
// since all actions have the same trigger
|
||||||
final ActionProperties firstAction = actions.values().iterator().next();
|
final ActionProperties firstAction = actions.values().iterator().next();
|
||||||
final Message message = getMessageConverter().toMessage(batchRequest,
|
final Message message = getMessageConverter().toMessage(
|
||||||
|
batchRequest,
|
||||||
createMessagePropertiesBatch(firstAction.getTenant(), getBatchEventTopicForAction(firstAction)));
|
createMessagePropertiesBatch(firstAction.getTenant(), getBatchEventTopicForAction(firstAction)));
|
||||||
amqpSenderService.sendMessage(message, firstTarget.getAddress());
|
amqpSenderService.sendMessage(message, firstTarget.getAddress());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import org.eclipse.hawkbit.dmf.json.model.DmfAutoConfirmation;
|
|||||||
import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing;
|
import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing;
|
||||||
import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode;
|
import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode;
|
||||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
|
||||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||||
@@ -51,6 +50,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
|||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||||
|
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||||
import org.eclipse.hawkbit.util.IpUtil;
|
import org.eclipse.hawkbit.util.IpUtil;
|
||||||
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
|
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
|
||||||
import org.springframework.amqp.core.Message;
|
import org.springframework.amqp.core.Message;
|
||||||
@@ -63,6 +63,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextImpl;
|
import org.springframework.security.core.context.SecurityContextImpl;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,6 +76,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
|
|
||||||
private static final String THING_ID_NULL = "ThingId is null";
|
private static final String THING_ID_NULL = "ThingId is null";
|
||||||
private static final String EMPTY_MESSAGE_BODY = "\"\"";
|
private static final String EMPTY_MESSAGE_BODY = "\"\"";
|
||||||
|
|
||||||
private final AmqpMessageDispatcherService amqpMessageDispatcherService;
|
private final AmqpMessageDispatcherService amqpMessageDispatcherService;
|
||||||
private final ConfirmationManagement confirmationManagement;
|
private final ConfirmationManagement confirmationManagement;
|
||||||
private final EntityFactory entityFactory;
|
private final EntityFactory entityFactory;
|
||||||
@@ -117,14 +119,15 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
* @return a message if <null> no message is send back to sender
|
* @return a message if <null> no message is send back to sender
|
||||||
*/
|
*/
|
||||||
@RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue:dmf_receiver}", containerFactory = "listenerContainerFactory")
|
@RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue:dmf_receiver}", containerFactory = "listenerContainerFactory")
|
||||||
public Message onMessage(final Message message,
|
public Message onMessage(
|
||||||
|
final Message message,
|
||||||
@Header(name = MessageHeaderKey.TYPE, required = false) final String type,
|
@Header(name = MessageHeaderKey.TYPE, required = false) final String type,
|
||||||
@Header(name = MessageHeaderKey.TENANT, required = false) final String tenant) {
|
@Header(name = MessageHeaderKey.TENANT, required = false) final String tenant) {
|
||||||
return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost());
|
return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * Executed if a amqp message arrives.
|
* Executed if a amqp message arrives.
|
||||||
*
|
*
|
||||||
* @param message the message
|
* @param message the message
|
||||||
* @param type the type
|
* @param type the type
|
||||||
@@ -133,7 +136,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
* @return the rpc message back to supplier.
|
* @return the rpc message back to supplier.
|
||||||
*/
|
*/
|
||||||
public Message onMessage(final Message message, final String type, final String tenant, final String virtualHost) {
|
public Message onMessage(final Message message, final String type, final String tenant, final String virtualHost) {
|
||||||
if (StringUtils.isEmpty(type) || StringUtils.isEmpty(tenant)) {
|
if (ObjectUtils.isEmpty(type) || ObjectUtils.isEmpty(tenant)) {
|
||||||
throw new AmqpRejectAndDontRequeueException("Invalid message! tenant and type header are mandatory!");
|
throw new AmqpRejectAndDontRequeueException("Invalid message! tenant and type header are mandatory!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,27 +144,32 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
try {
|
try {
|
||||||
final MessageType messageType = MessageType.valueOf(type);
|
final MessageType messageType = MessageType.valueOf(type);
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
case THING_CREATED:
|
case THING_CREATED: {
|
||||||
setTenantSecurityContext(tenant);
|
setTenantSecurityContext(tenant);
|
||||||
registerTarget(message, virtualHost);
|
registerTarget(message, virtualHost);
|
||||||
break;
|
break;
|
||||||
case THING_REMOVED:
|
}
|
||||||
|
case THING_REMOVED: {
|
||||||
setTenantSecurityContext(tenant);
|
setTenantSecurityContext(tenant);
|
||||||
deleteTarget(message);
|
deleteTarget(message);
|
||||||
break;
|
break;
|
||||||
case EVENT:
|
}
|
||||||
|
case EVENT: {
|
||||||
checkContentTypeJson(message);
|
checkContentTypeJson(message);
|
||||||
setTenantSecurityContext(tenant);
|
setTenantSecurityContext(tenant);
|
||||||
handleIncomingEvent(message);
|
handleIncomingEvent(message);
|
||||||
break;
|
break;
|
||||||
case PING:
|
}
|
||||||
|
case PING: {
|
||||||
if (isCorrelationIdNotEmpty(message)) {
|
if (isCorrelationIdNotEmpty(message)) {
|
||||||
amqpMessageDispatcherService.sendPingReponseToDmfReceiver(message, tenant, virtualHost);
|
amqpMessageDispatcherService.sendPingResponseToDmfReceiver(message, tenant, virtualHost);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
logAndThrowMessageError(message, "No handle method was found for the given message type.");
|
logAndThrowMessageError(message, "No handle method was found for the given message type.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (AssignmentQuotaExceededException ex) {
|
} catch (AssignmentQuotaExceededException ex) {
|
||||||
throw new AmqpRejectAndDontRequeueException("Could not handle message due to quota violation!", ex);
|
throw new AmqpRejectAndDontRequeueException("Could not handle message due to quota violation!", ex);
|
||||||
} catch (final IllegalArgumentException ex) {
|
} catch (final IllegalArgumentException ex) {
|
||||||
@@ -212,40 +220,51 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
final Action action) {
|
final Action action) {
|
||||||
Status status = null;
|
Status status = null;
|
||||||
switch (actionUpdateStatus.getActionStatus()) {
|
switch (actionUpdateStatus.getActionStatus()) {
|
||||||
case DOWNLOAD:
|
case DOWNLOAD: {
|
||||||
status = Status.DOWNLOAD;
|
status = Status.DOWNLOAD;
|
||||||
break;
|
break;
|
||||||
case RETRIEVED:
|
}
|
||||||
|
case RETRIEVED: {
|
||||||
status = Status.RETRIEVED;
|
status = Status.RETRIEVED;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RUNNING:
|
case RUNNING:
|
||||||
case CONFIRMED:
|
case CONFIRMED: {
|
||||||
status = Status.RUNNING;
|
status = Status.RUNNING;
|
||||||
break;
|
break;
|
||||||
case CANCELED:
|
}
|
||||||
|
case CANCELED: {
|
||||||
status = Status.CANCELED;
|
status = Status.CANCELED;
|
||||||
break;
|
break;
|
||||||
case FINISHED:
|
}
|
||||||
|
case FINISHED: {
|
||||||
status = Status.FINISHED;
|
status = Status.FINISHED;
|
||||||
break;
|
break;
|
||||||
case ERROR:
|
}
|
||||||
|
case ERROR: {
|
||||||
status = Status.ERROR;
|
status = Status.ERROR;
|
||||||
break;
|
break;
|
||||||
case WARNING:
|
}
|
||||||
|
case WARNING: {
|
||||||
status = Status.WARNING;
|
status = Status.WARNING;
|
||||||
break;
|
break;
|
||||||
case DOWNLOADED:
|
}
|
||||||
|
case DOWNLOADED: {
|
||||||
status = Status.DOWNLOADED;
|
status = Status.DOWNLOADED;
|
||||||
break;
|
break;
|
||||||
case CANCEL_REJECTED:
|
}
|
||||||
|
case CANCEL_REJECTED: {
|
||||||
status = handleCancelRejectedState(message, action);
|
status = handleCancelRejectedState(message, action);
|
||||||
break;
|
break;
|
||||||
case DENIED:
|
}
|
||||||
|
case DENIED: {
|
||||||
status = Status.WAIT_FOR_CONFIRMATION;
|
status = Status.WAIT_FOR_CONFIRMATION;
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
logAndThrowMessageError(message, "Status for action does not exisit.");
|
logAndThrowMessageError(message, "Status for action does not exisit.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -254,7 +273,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
if (action.isCancelingOrCanceled()) {
|
if (action.isCancelingOrCanceled()) {
|
||||||
return Status.CANCEL_REJECTED;
|
return Status.CANCEL_REJECTED;
|
||||||
}
|
}
|
||||||
logAndThrowMessageError(message,
|
logAndThrowMessageError(
|
||||||
|
message,
|
||||||
"Cancel rejected message is not allowed, if action is on state: " + action.getStatus());
|
"Cancel rejected message is not allowed, if action is on state: " + action.getStatus());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -274,15 +294,14 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
* Method to create a new target or to find the target if it already exists
|
* Method to create a new target or to find the target if it already exists
|
||||||
* and update its poll time, status and optionally its name and attributes.
|
* and update its poll time, status and optionally its name and attributes.
|
||||||
*
|
*
|
||||||
* @param message the message that contains replyTo property and optionally the
|
* @param message the message that contains replyTo property and optionally the name and attributes in body
|
||||||
* name and attributes in body
|
|
||||||
* @param virtualHost the virtual host
|
* @param virtualHost the virtual host
|
||||||
*/
|
*/
|
||||||
private void registerTarget(final Message message, final String virtualHost) {
|
private void registerTarget(final Message message, final String virtualHost) {
|
||||||
final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL);
|
final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL);
|
||||||
final String replyTo = message.getMessageProperties().getReplyTo();
|
final String replyTo = message.getMessageProperties().getReplyTo();
|
||||||
|
|
||||||
if (StringUtils.isEmpty(replyTo)) {
|
if (ObjectUtils.isEmpty(replyTo)) {
|
||||||
logAndThrowMessageError(message, "No ReplyTo was set for the createThing message.");
|
logAndThrowMessageError(message, "No ReplyTo was set for the createThing message.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,22 +316,22 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
final DmfCreateThing thingCreateBody = convertMessage(message, DmfCreateThing.class);
|
final DmfCreateThing thingCreateBody = convertMessage(message, DmfCreateThing.class);
|
||||||
final DmfAttributeUpdate thingAttributeUpdateBody = thingCreateBody.getAttributeUpdate();
|
final DmfAttributeUpdate thingAttributeUpdateBody = thingCreateBody.getAttributeUpdate();
|
||||||
|
|
||||||
log.debug("Received \"THING_CREATED\" AMQP message for thing \"{}\" with target name \"{}\" and type " +
|
log.debug(
|
||||||
"\"{}\".", thingId, thingCreateBody.getName(), thingCreateBody.getType());
|
"Received \"THING_CREATED\" AMQP message for thing \"{}\" with target name \"{}\" and type \"{}\".",
|
||||||
|
thingId, thingCreateBody.getName(), thingCreateBody.getType());
|
||||||
|
|
||||||
target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri,
|
target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(
|
||||||
thingCreateBody.getName(), thingCreateBody.getType());
|
thingId, amqpUri, thingCreateBody.getName(), thingCreateBody.getType());
|
||||||
|
|
||||||
if (thingAttributeUpdateBody != null) {
|
if (thingAttributeUpdateBody != null) {
|
||||||
controllerManagement.updateControllerAttributes(thingId, thingAttributeUpdateBody.getAttributes(),
|
controllerManagement.updateControllerAttributes(
|
||||||
getUpdateMode(thingAttributeUpdateBody));
|
thingId, thingAttributeUpdateBody.getAttributes(), getUpdateMode(thingAttributeUpdateBody));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.debug("Target {} reported online state.", thingId);
|
log.debug("Target {} reported online state.", thingId);
|
||||||
sendUpdateCommandToTarget(target);
|
sendUpdateCommandToTarget(target);
|
||||||
} catch (final EntityAlreadyExistsException e) {
|
} catch (final EntityAlreadyExistsException e) {
|
||||||
throw new AmqpRejectAndDontRequeueException(
|
throw new AmqpRejectAndDontRequeueException("Tried to register previously registered target, message will be ignored!", e);
|
||||||
"Tried to register previously registered target, message will be ignored!", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,23 +344,21 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendCurrentActionsAsMultiActionToTarget(final Target target) {
|
private void sendCurrentActionsAsMultiActionToTarget(final Target target) {
|
||||||
final List<Action> actions = controllerManagement.findActiveActionsWithHighestWeight(target.getControllerId(),
|
final List<Action> actions = controllerManagement.findActiveActionsWithHighestWeight(target.getControllerId(), MAX_ACTION_COUNT);
|
||||||
MAX_ACTION_COUNT);
|
|
||||||
|
|
||||||
final Set<DistributionSet> distributionSets = actions.stream().map(Action::getDistributionSet)
|
final Set<DistributionSet> distributionSets = actions.stream().map(Action::getDistributionSet).collect(Collectors.toSet());
|
||||||
.collect(Collectors.toSet());
|
|
||||||
final Map<Long, Map<SoftwareModule, List<SoftwareModuleMetadata>>> softwareModulesPerDistributionSet = distributionSets
|
final Map<Long, Map<SoftwareModule, List<SoftwareModuleMetadata>>> softwareModulesPerDistributionSet = distributionSets
|
||||||
.stream().collect(Collectors.toMap(DistributionSet::getId, this::getSoftwareModulesWithMetadata));
|
.stream().collect(Collectors.toMap(DistributionSet::getId, this::getSoftwareModulesWithMetadata));
|
||||||
|
|
||||||
amqpMessageDispatcherService.sendMultiActionRequestToTarget(target.getTenant(), target, actions,
|
amqpMessageDispatcherService.sendMultiActionRequestToTarget(
|
||||||
|
target.getTenant(), target, actions,
|
||||||
action -> softwareModulesPerDistributionSet.get(action.getDistributionSet().getId()));
|
action -> softwareModulesPerDistributionSet.get(action.getDistributionSet().getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendOldestActionToTarget(final Target target) {
|
private void sendOldestActionToTarget(final Target target) {
|
||||||
final Optional<Action> actionOptional = controllerManagement
|
final Optional<Action> actionOptional = controllerManagement.findActiveActionWithHighestWeight(target.getControllerId());
|
||||||
.findActiveActionWithHighestWeight(target.getControllerId());
|
|
||||||
|
|
||||||
if (!actionOptional.isPresent()) {
|
if (actionOptional.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,8 +372,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<SoftwareModule, List<SoftwareModuleMetadata>> getSoftwareModulesWithMetadata(
|
private Map<SoftwareModule, List<SoftwareModuleMetadata>> getSoftwareModulesWithMetadata(final DistributionSet distributionSet) {
|
||||||
final DistributionSet distributionSet) {
|
|
||||||
final List<Long> smIds = distributionSet.getModules().stream().map(SoftwareModule::getId)
|
final List<Long> smIds = distributionSet.getModules().stream().map(SoftwareModule::getId)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
@@ -375,20 +391,23 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
*/
|
*/
|
||||||
private void handleIncomingEvent(final Message message) {
|
private void handleIncomingEvent(final Message message) {
|
||||||
switch (EventTopic.valueOf(getStringHeaderKey(message, MessageHeaderKey.TOPIC, "EventTopic is null"))) {
|
switch (EventTopic.valueOf(getStringHeaderKey(message, MessageHeaderKey.TOPIC, "EventTopic is null"))) {
|
||||||
case UPDATE_ACTION_STATUS:
|
case UPDATE_ACTION_STATUS: {
|
||||||
updateActionStatus(message);
|
updateActionStatus(message);
|
||||||
break;
|
break;
|
||||||
case UPDATE_ATTRIBUTES:
|
}
|
||||||
|
case UPDATE_ATTRIBUTES: {
|
||||||
updateAttributes(message);
|
updateAttributes(message);
|
||||||
break;
|
break;
|
||||||
case UPDATE_AUTO_CONFIRM:
|
}
|
||||||
|
case UPDATE_AUTO_CONFIRM: {
|
||||||
setAutoConfirmationState(message);
|
setAutoConfirmationState(message);
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
logAndThrowMessageError(message, "Got event without appropriate topic.");
|
logAndThrowMessageError(message, "Got event without appropriate topic.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteTarget(final Message message) {
|
private void deleteTarget(final Message message) {
|
||||||
@@ -400,8 +419,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class);
|
final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class);
|
||||||
final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL);
|
final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL);
|
||||||
|
|
||||||
controllerManagement.updateControllerAttributes(thingId, attributeUpdate.getAttributes(),
|
controllerManagement.updateControllerAttributes(thingId, attributeUpdate.getAttributes(), getUpdateMode(attributeUpdate));
|
||||||
getUpdateMode(attributeUpdate));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAutoConfirmationState(final Message message) {
|
private void setAutoConfirmationState(final Message message) {
|
||||||
@@ -439,22 +457,19 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
final Status status = mapStatus(message, actionUpdateStatus, action);
|
final Status status = mapStatus(message, actionUpdateStatus, action);
|
||||||
|
|
||||||
final Action updatedAction;
|
final Action updatedAction;
|
||||||
|
|
||||||
if (actionUpdateStatus.getActionStatus() == DmfActionStatus.CONFIRMED) {
|
if (actionUpdateStatus.getActionStatus() == DmfActionStatus.CONFIRMED) {
|
||||||
updatedAction = confirmationManagement.confirmAction(action.getId(),
|
updatedAction = confirmationManagement.confirmAction(action.getId(),
|
||||||
actionUpdateStatus.getCode().orElse(null), messages);
|
actionUpdateStatus.getCode().orElse(null), messages);
|
||||||
} else if (actionUpdateStatus.getActionStatus() == DmfActionStatus.DENIED) {
|
} else if (actionUpdateStatus.getActionStatus() == DmfActionStatus.DENIED) {
|
||||||
updatedAction = confirmationManagement.denyAction(action.getId(), actionUpdateStatus.getCode().orElse(null),
|
updatedAction = confirmationManagement.denyAction(action.getId(), actionUpdateStatus.getCode().orElse(null), messages);
|
||||||
messages);
|
|
||||||
} else {
|
} else {
|
||||||
final ActionStatusCreate actionStatus = entityFactory.actionStatus().create(action.getId()).status(status)
|
final ActionStatusCreate actionStatus = entityFactory.actionStatus().create(action.getId()).status(status).messages(messages);
|
||||||
.messages(messages);
|
|
||||||
actionUpdateStatus.getCode().ifPresent(code -> {
|
actionUpdateStatus.getCode().ifPresent(code -> {
|
||||||
actionStatus.code(code);
|
actionStatus.code(code);
|
||||||
actionStatus.message("Device reported status code: " + code);
|
actionStatus.message("Device reported status code: " + code);
|
||||||
});
|
});
|
||||||
updatedAction = ((Status.CANCELED == status) || (Status.CANCEL_REJECTED == status)) ?
|
updatedAction = ((Status.CANCELED == status) || (Status.CANCEL_REJECTED == status))
|
||||||
controllerManagement.addCancelActionStatus(actionStatus)
|
? controllerManagement.addCancelActionStatus(actionStatus)
|
||||||
: controllerManagement.addUpdateActionStatus(actionStatus);
|
: controllerManagement.addUpdateActionStatus(actionStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,8 +478,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exception squid:S3655 - logAndThrowMessageError throws exception, i.e.
|
// Exception squid:S3655 - logAndThrowMessageError throws exception, i.e. get will not be called
|
||||||
// get will not be called
|
|
||||||
@SuppressWarnings("squid:S3655")
|
@SuppressWarnings("squid:S3655")
|
||||||
private Action checkActionExist(final Message message, final DmfActionUpdateStatus actionUpdateStatus) {
|
private Action checkActionExist(final Message message, final DmfActionUpdateStatus actionUpdateStatus) {
|
||||||
final Long actionId = actionUpdateStatus.getActionId();
|
final Long actionId = actionUpdateStatus.getActionId();
|
||||||
@@ -473,9 +487,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
actionUpdateStatus.getActionStatus());
|
actionUpdateStatus.getActionStatus());
|
||||||
|
|
||||||
final Optional<Action> findActionWithDetails = controllerManagement.findActionWithDetails(actionId);
|
final Optional<Action> findActionWithDetails = controllerManagement.findActionWithDetails(actionId);
|
||||||
if (!findActionWithDetails.isPresent()) {
|
if (findActionWithDetails.isEmpty()) {
|
||||||
logAndThrowMessageError(message,
|
logAndThrowMessageError(message, "Got intermediate notification about action " + actionId + " but action does not exist");
|
||||||
"Got intermediate notification about action " + actionId + " but action does not exist");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return findActionWithDetails.get();
|
return findActionWithDetails.get();
|
||||||
@@ -486,7 +499,6 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Serializable> T getConfigValue(final String key, final Class<T> valueType) {
|
private <T extends Serializable> T getConfigValue(final String key, final Class<T> valueType) {
|
||||||
return systemSecurityContext
|
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue());
|
||||||
.runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public interface AmqpMessageSenderService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the given message to the given uri. The uri contains the (virtual)
|
* Send the given message to the given uri. The uri contains the (virtual)
|
||||||
* host and exchange e.g amqp://host/exchange.
|
* host and exchange e.g. amqp://host/exchange.
|
||||||
*
|
*
|
||||||
* @param message the amqp message
|
* @param message the amqp message
|
||||||
* @param replyTo the reply to uri
|
* @param replyTo the reply to uri
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||||||
public class AmqpProperties {
|
public class AmqpProperties {
|
||||||
|
|
||||||
private static final int DEFAULT_QUEUE_DECLARATION_RETRIES = 50;
|
private static final int DEFAULT_QUEUE_DECLARATION_RETRIES = 50;
|
||||||
|
|
||||||
private static final long DEFAULT_REQUEUE_DELAY = 0;
|
private static final long DEFAULT_REQUEUE_DELAY = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ public class BaseAmqpService {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T convertMessage(@NotNull final Message message, final Class<T> clazz) {
|
public <T> T convertMessage(@NotNull final Message message, final Class<T> clazz) {
|
||||||
checkMessageBody(message);
|
checkMessageBody(message);
|
||||||
message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME,
|
message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME, clazz.getName());
|
||||||
clazz.getName());
|
|
||||||
return (T) rabbitTemplate.getMessageConverter().fromMessage(message);
|
return (T) rabbitTemplate.getMessageConverter().fromMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,5 +103,4 @@ public class BaseAmqpService {
|
|||||||
protected void cleanMessageHeaderProperties(final Message message) {
|
protected void cleanMessageHeaderProperties(final Message message) {
|
||||||
message.getMessageProperties().getHeaders().remove(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME);
|
message.getMessageProperties().getHeaders().remove(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -31,20 +31,19 @@ public class ConfigurableRabbitListenerContainerFactory extends SimpleRabbitList
|
|||||||
* @param errorHandler the error handler which should be use
|
* @param errorHandler the error handler which should be use
|
||||||
* @see SimpleMessageListenerContainer#setMissingQueuesFatal
|
* @see SimpleMessageListenerContainer#setMissingQueuesFatal
|
||||||
*/
|
*/
|
||||||
public ConfigurableRabbitListenerContainerFactory(final boolean missingQueuesFatal, final int declarationRetries,
|
public ConfigurableRabbitListenerContainerFactory(
|
||||||
final ErrorHandler errorHandler) {
|
final boolean missingQueuesFatal, final int declarationRetries, final ErrorHandler errorHandler) {
|
||||||
this.declarationRetries = declarationRetries;
|
this.declarationRetries = declarationRetries;
|
||||||
|
|
||||||
setErrorHandler(errorHandler);
|
setErrorHandler(errorHandler);
|
||||||
setMissingQueuesFatal(missingQueuesFatal);
|
setMissingQueuesFatal(missingQueuesFatal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
// Exception squid:UnusedProtectedMethod - called by
|
// Exception squid:UnusedProtectedMethod - called by
|
||||||
// AbstractRabbitListenerContainerFactory
|
// AbstractRabbitListenerContainerFactory
|
||||||
@SuppressWarnings("squid:UnusedProtectedMethod")
|
@SuppressWarnings("squid:UnusedProtectedMethod")
|
||||||
protected void initializeContainer(final SimpleMessageListenerContainer instance,
|
@Override
|
||||||
final RabbitListenerEndpoint endpoint) {
|
protected void initializeContainer(final SimpleMessageListenerContainer instance, final RabbitListenerEndpoint endpoint) {
|
||||||
super.initializeContainer(instance, endpoint);
|
super.initializeContainer(instance, endpoint);
|
||||||
instance.setDeclarationRetries(declarationRetries);
|
instance.setDeclarationRetries(declarationRetries);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,5 +61,4 @@ public class DefaultAmqpMessageSenderService extends BaseAmqpService implements
|
|||||||
protected static boolean isCorrelationIdEmpty(final Message message) {
|
protected static boolean isCorrelationIdEmpty(final Message message) {
|
||||||
return !StringUtils.hasLength(message.getMessageProperties().getCorrelationId());
|
return !StringUtils.hasLength(message.getMessageProperties().getCorrelationId());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,8 @@ public class DelayedRequeueExceptionStrategy extends ConditionalRejectingErrorHa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isMessageException(final Throwable cause) {
|
private static boolean isMessageException(final Throwable cause) {
|
||||||
return cause instanceof InvalidTargetAddressException || cause instanceof MessageConversionException
|
return cause instanceof InvalidTargetAddressException ||
|
||||||
|| cause instanceof MessageHandlingException;
|
cause instanceof MessageConversionException ||
|
||||||
|
cause instanceof MessageHandlingException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,4 @@ import org.springframework.context.annotation.Import;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan
|
@ComponentScan
|
||||||
@Import(AmqpConfiguration.class)
|
@Import(AmqpConfiguration.class)
|
||||||
public class DmfApiConfiguration {
|
public class DmfApiConfiguration {}
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user