Notes: 1. (!) Eclipselink shall be migrated to 5.0 (in 4.0.8 there are incompatible classes, e.g EJBQueryImpl doesn't implement some newer methods). In the moment is with beta (5.0.0-B12) - JUST for testing! 2. (!) Ethlo plugin doesn't work with Eclipselink 5.0, it builds with Eclipselink 4.0.8 (could be a problem) 3. Dependencies - new starters, test starters changes, some dependencies refactoring 4. Auto-configs split - package changes, some properties classes changes 5. Spring nullable org.springframework.lang.Nullable/NonNull are depecated and replaced with jspcify -> org.jspecify.annotations.Nullable/NonNull (NullMarked) 6. Lombok config - adding lombok.addNullAnnotations=jspecify - to do not mess annotations 7. Distributed lock table changes - SP_LOCK table db migration 8. Spring Retry replaced with Spring Core Retry - does repace retry in hawkbit 9. Specifications -> added Update/Delete(/Predicate) Specifications and JpaSpecificationExecutor changed 10. HawkbitBaseRepositoryFactoryBean modified to register properly 11. Jackson - 2 -> 3, package migrations, finals are not deserialized by default(enable finals deserialization, consider make non-final), too ‘smart’ tries to set complex objects instead of using non args constructor (-> @JsonIgnore), some other default configs made Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -27,26 +27,5 @@
|
|||||||
<artifactId>hawkbit-core</artifactId>
|
<artifactId>hawkbit-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.security</groupId>
|
|
||||||
<artifactId>spring-security-config</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.validation</groupId>
|
|
||||||
<artifactId>jakarta.validation-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- TEST -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.github.classgraph</groupId>
|
|
||||||
<artifactId>classgraph</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -27,18 +27,5 @@
|
|||||||
<artifactId>hawkbit-artifact-api</artifactId>
|
<artifactId>hawkbit-artifact-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-io</groupId>
|
|
||||||
<artifactId>commons-io</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -19,7 +19,6 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.eclipse.hawkbit.artifact.AbstractArtifactStorage;
|
import org.eclipse.hawkbit.artifact.AbstractArtifactStorage;
|
||||||
import org.eclipse.hawkbit.artifact.ArtifactStorage;
|
import org.eclipse.hawkbit.artifact.ArtifactStorage;
|
||||||
import org.eclipse.hawkbit.artifact.exception.ArtifactBinaryNotFoundException;
|
import org.eclipse.hawkbit.artifact.exception.ArtifactBinaryNotFoundException;
|
||||||
@@ -47,7 +46,7 @@ public class FileArtifactStorage extends AbstractArtifactStorage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteBySha1(final String tenant, final String sha1) {
|
public void deleteBySha1(final String tenant, final String sha1) {
|
||||||
FileUtils.deleteQuietly(getFile(tenant, sha1));
|
deleteSilent(getFile(tenant, sha1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,7 +64,7 @@ public class FileArtifactStorage extends AbstractArtifactStorage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteByTenant(final String tenant) {
|
public void deleteByTenant(final String tenant) {
|
||||||
FileUtils.deleteQuietly(Paths.get(artifactResourceProperties.getPath(), sanitizeTenant(tenant)).toFile());
|
deleteSilent(Paths.get(artifactResourceProperties.getPath(), sanitizeTenant(tenant)).toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,7 +77,7 @@ public class FileArtifactStorage extends AbstractArtifactStorage {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
final File fileSHA1Naming = getFile(tenant, base16Hashes.sha1());
|
final File fileSHA1Naming = getFile(tenant, base16Hashes.sha1());
|
||||||
if (fileSHA1Naming.exists()) {
|
if (fileSHA1Naming.exists()) {
|
||||||
FileUtils.deleteQuietly(tempFile);
|
deleteSilent(tempFile);
|
||||||
} else {
|
} else {
|
||||||
Files.move(tempFile.toPath(), fileSHA1Naming.toPath());
|
Files.move(tempFile.toPath(), fileSHA1Naming.toPath());
|
||||||
}
|
}
|
||||||
@@ -107,4 +106,24 @@ public class FileArtifactStorage extends AbstractArtifactStorage {
|
|||||||
final String folder2 = sha1.substring(length - 2, length);
|
final String folder2 = sha1.substring(length - 2, length);
|
||||||
return Paths.get(artifactResourceProperties.getPath(), sanitizeTenant(tenant), folder1, folder2);
|
return Paths.get(artifactResourceProperties.getPath(), sanitizeTenant(tenant), folder1, folder2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "java:S899", "java:S4042" }) // just ignore the result - silent
|
||||||
|
private static void deleteSilent(final File file) {
|
||||||
|
if (file.exists()) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
// delete children
|
||||||
|
final File[] children = file.listFiles();
|
||||||
|
if (children != null) {
|
||||||
|
for (final File child : children) {
|
||||||
|
deleteSilent(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
file.delete(); // silent
|
||||||
|
} catch (final Exception ignored) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -15,11 +15,11 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.assertj.core.api.Assertions;
|
import org.assertj.core.api.Assertions;
|
||||||
import org.eclipse.hawkbit.artifact.AbstractArtifactStorage;
|
import org.eclipse.hawkbit.artifact.AbstractArtifactStorage;
|
||||||
import org.eclipse.hawkbit.artifact.exception.ArtifactBinaryNotFoundException;
|
import org.eclipse.hawkbit.artifact.exception.ArtifactBinaryNotFoundException;
|
||||||
@@ -54,7 +54,7 @@ class FileArtifactStorageTest {
|
|||||||
static void afterClass() {
|
static void afterClass() {
|
||||||
if (new File(artifactResourceProperties.getPath()).exists()) {
|
if (new File(artifactResourceProperties.getPath()).exists()) {
|
||||||
try {
|
try {
|
||||||
FileUtils.deleteDirectory(new File(artifactResourceProperties.getPath()));
|
delete(new File(artifactResourceProperties.getPath()));
|
||||||
} catch (final IOException | IllegalArgumentException e) {
|
} catch (final IOException | IllegalArgumentException e) {
|
||||||
log.warn("Cannot delete file-directory", e);
|
log.warn("Cannot delete file-directory", e);
|
||||||
}
|
}
|
||||||
@@ -69,9 +69,10 @@ class FileArtifactStorageTest {
|
|||||||
final byte[] fileContent = randomBytes();
|
final byte[] fileContent = randomBytes();
|
||||||
final StoredArtifactInfo artifact = storeRandomArtifact(fileContent);
|
final StoredArtifactInfo artifact = storeRandomArtifact(fileContent);
|
||||||
|
|
||||||
final byte[] readContent = new byte[fileContent.length];
|
try (final InputStream is = artifactFilesystemRepository.getBySha1(TENANT, artifact.getHashes().sha1())) {
|
||||||
IOUtils.read(artifactFilesystemRepository.getBySha1(TENANT, artifact.getHashes().sha1()), readContent);
|
final byte[] readContent = is.readAllBytes();
|
||||||
assertThat(readContent).isEqualTo(fileContent);
|
assertThat(readContent).isEqualTo(fileContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,4 +142,20 @@ class FileArtifactStorageTest {
|
|||||||
return artifactFilesystemRepository.store(TENANT, inputStream, "filename.tmp", "application/txt", null);
|
return artifactFilesystemRepository.store(TENANT, inputStream, "filename.tmp", "application/txt", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void delete(final File file) throws IOException {
|
||||||
|
if (file.exists()) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
// delete children
|
||||||
|
final File[] children = file.listFiles();
|
||||||
|
if (children != null) {
|
||||||
|
for (final File child : children) {
|
||||||
|
delete(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Files.delete(file.toPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -44,13 +44,6 @@
|
|||||||
<artifactId>protostuff-core</artifactId>
|
<artifactId>protostuff-core</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.servlet</groupId>
|
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.protostuff</groupId>
|
<groupId>io.protostuff</groupId>
|
||||||
<artifactId>protostuff-runtime</artifactId>
|
<artifactId>protostuff-runtime</artifactId>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
|||||||
import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties;
|
import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.boot.security.autoconfigure.SecurityProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ package org.eclipse.hawkbit.autoconfigure.security;
|
|||||||
|
|
||||||
import org.eclipse.hawkbit.auth.StaticAuthenticationProvider;
|
import org.eclipse.hawkbit.auth.StaticAuthenticationProvider;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties;
|
import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties;
|
||||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.boot.security.autoconfigure.SecurityProperties;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
|||||||
@@ -24,72 +24,43 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot</artifactId>
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.security</groupId>
|
|
||||||
<artifactId>spring-security-config</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
|
<artifactId>spring-boot-starter-security-oauth2-client</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-web</artifactId>
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-data-commons</artifactId>
|
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-context-support</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-security-oauth2-core</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.security</groupId>
|
|
||||||
<artifactId>spring-security-aspects</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.security</groupId>
|
|
||||||
<artifactId>spring-security-web</artifactId>
|
|
||||||
<!-- needed for web MDC filter -->
|
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>tools.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.validation</groupId>
|
<groupId>jakarta.validation</groupId>
|
||||||
<artifactId>jakarta.validation-api</artifactId>
|
<artifactId>jakarta.validation-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.servlet</groupId>
|
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.micrometer</groupId>
|
|
||||||
<artifactId>micrometer-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
<artifactId>caffeine</artifactId>
|
<artifactId>caffeine</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
<!-- needed for JSON context serialization -->
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- TEST -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.github.classgraph</groupId>
|
|
||||||
<artifactId>classgraph</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made
|
||||||
|
* available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit;
|
||||||
|
|
||||||
|
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link HawkbitAutoConfiguration} brings some default configurations needed for hawkbit. It does:
|
||||||
|
* <ul>
|
||||||
|
* <li>Import {@link JacksonAutoConfiguration} and applies hawkbit-jackson-defaults.properties in order to configure the {@link tools.jackson.databind.json.JsonMapper}.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Import(JacksonAutoConfiguration.class)
|
||||||
|
@PropertySource("classpath:/hawkbit-jackson-defaults.properties")
|
||||||
|
public class HawkbitAutoConfiguration {}
|
||||||
@@ -20,7 +20,7 @@ import java.util.regex.Pattern;
|
|||||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAwareUser;
|
import org.eclipse.hawkbit.tenancy.TenantAwareUser;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties;
|
import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties;
|
||||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
import org.springframework.boot.security.autoconfigure.SecurityProperties;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import java.util.function.Supplier;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@@ -36,6 +34,7 @@ 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.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A 'static' class providing methods related to access context:
|
* A 'static' class providing methods related to access context:
|
||||||
@@ -298,11 +297,7 @@ public class AccessContext {
|
|||||||
@SuppressWarnings("java:S112") // java:S112 - generic method
|
@SuppressWarnings("java:S112") // java:S112 - generic method
|
||||||
private static String serialize(final SecurityContext securityContext) {
|
private static String serialize(final SecurityContext securityContext) {
|
||||||
Objects.requireNonNull(securityContext);
|
Objects.requireNonNull(securityContext);
|
||||||
try {
|
return OBJECT_MAPPER.writeValueAsString(new SecCtxInfo(securityContext));
|
||||||
return OBJECT_MAPPER.writeValueAsString(new SecCtxInfo(securityContext));
|
|
||||||
} catch (final JsonProcessingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -314,12 +309,7 @@ public class AccessContext {
|
|||||||
@SuppressWarnings("java:S112") // java:S112 - generic method
|
@SuppressWarnings("java:S112") // java:S112 - generic method
|
||||||
private static SecurityContext deserialize(final String securityContextString) {
|
private static SecurityContext deserialize(final String securityContextString) {
|
||||||
Objects.requireNonNull(securityContextString);
|
Objects.requireNonNull(securityContextString);
|
||||||
final String securityContextTrimmed = securityContextString.trim();
|
return OBJECT_MAPPER.readerFor(SecCtxInfo.class).<SecCtxInfo> readValue(securityContextString.trim()).toSecurityContext();
|
||||||
try {
|
|
||||||
return OBJECT_MAPPER.readerFor(SecCtxInfo.class).<SecCtxInfo> readValue(securityContextTrimmed).toSecurityContext();
|
|
||||||
} catch (final JsonProcessingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAuthenticationInvalid(final Authentication authentication) {
|
private static boolean isAuthenticationInvalid(final Authentication authentication) {
|
||||||
|
|||||||
@@ -14,31 +14,29 @@ import java.util.NoSuchElementException;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import jakarta.servlet.DispatcherType;
|
||||||
|
|
||||||
import io.micrometer.common.KeyValue;
|
import io.micrometer.common.KeyValue;
|
||||||
import io.micrometer.common.KeyValues;
|
import io.micrometer.common.KeyValues;
|
||||||
import io.micrometer.core.instrument.Tag;
|
import io.micrometer.core.instrument.Tag;
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import org.eclipse.hawkbit.context.AccessContext;
|
import org.eclipse.hawkbit.context.AccessContext;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties;
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration;
|
|
||||||
import org.springframework.boot.actuate.metrics.data.DefaultRepositoryTagsProvider;
|
|
||||||
import org.springframework.boot.actuate.metrics.data.RepositoryTagsProvider;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
import org.springframework.boot.data.metrics.DefaultRepositoryTagsProvider;
|
||||||
|
import org.springframework.boot.data.metrics.RepositoryTagsProvider;
|
||||||
|
import org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterProperties;
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.data.repository.core.support.RepositoryMethodInvocationListener;
|
import org.springframework.data.repository.core.support.RepositoryMethodInvocationListener;
|
||||||
import org.springframework.http.server.observation.DefaultServerRequestObservationConvention;
|
import org.springframework.http.server.observation.DefaultServerRequestObservationConvention;
|
||||||
import org.springframework.http.server.observation.ServerRequestObservationContext;
|
import org.springframework.http.server.observation.ServerRequestObservationContext;
|
||||||
import org.springframework.http.server.observation.ServerRequestObservationConvention;
|
|
||||||
import org.springframework.web.filter.ServerHttpObservationFilter;
|
import org.springframework.web.filter.ServerHttpObservationFilter;
|
||||||
|
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@@ -57,11 +55,11 @@ public class DefaultTenantConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AutoConfiguration(afterName = {
|
@AutoConfiguration(afterName = {
|
||||||
"org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration",
|
"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration",
|
||||||
"org.eclipse.hawkbit.autoconfigure.security.SecurityAutoConfiguration" })
|
"org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration" })
|
||||||
@ConditionalOnProperty(name = "hawkbit.metrics.tenancy.web.enabled", havingValue = "true", matchIfMissing = true)
|
@ConditionalOnProperty(name = "hawkbit.metrics.tenancy.web.enabled", havingValue = "true", matchIfMissing = true)
|
||||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||||
@ConditionalOnClass(name = { "org.springframework.web.servlet.DispatcherServlet", "io.micrometer.observation.Observation" })
|
@ConditionalOnClass(name = { "io.micrometer.observation.Observation", "org.springframework.web.servlet.DispatcherServlet" })
|
||||||
@ConditionalOnBean(ObservationRegistry.class)
|
@ConditionalOnBean(ObservationRegistry.class)
|
||||||
public static class WebConfig {
|
public static class WebConfig {
|
||||||
|
|
||||||
@@ -87,31 +85,40 @@ public class DefaultTenantConfiguration {
|
|||||||
@Primary
|
@Primary
|
||||||
public FilterRegistrationBean<ServerHttpObservationFilter> webMvcObservationFilter(
|
public FilterRegistrationBean<ServerHttpObservationFilter> webMvcObservationFilter(
|
||||||
final ObservationRegistry registry,
|
final ObservationRegistry registry,
|
||||||
// should be serverRequestObservationConvention (registered above)
|
final SecurityFilterProperties securityFilterProperties) {
|
||||||
final ObjectProvider<ServerRequestObservationConvention> customConvention,
|
final FilterRegistrationBean<ServerHttpObservationFilter> filterRegistrationBean = new FilterRegistrationBean<>(
|
||||||
final ObservationProperties observationProperties,
|
new ServerHttpObservationFilter(registry, new DefaultServerRequestObservationConvention() {
|
||||||
final SecurityProperties securityProperties) {
|
|
||||||
final FilterRegistrationBean<ServerHttpObservationFilter> filterRegistrationBean = new WebMvcObservationAutoConfiguration()
|
@NonNull
|
||||||
.webMvcObservationFilter(registry, customConvention, observationProperties);
|
@Override
|
||||||
|
public KeyValues getLowCardinalityKeyValues(@NonNull final ServerRequestObservationContext context) {
|
||||||
|
// Make sure that KeyValues entries are already sorted by name for better performance
|
||||||
|
return KeyValues.of(exception(context), method(context), outcome(context), status(context), tenant(), uri(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KeyValue tenant() {
|
||||||
|
return KeyValue.of(TENANT_TAG, Optional.ofNullable(AccessContext.tenant()).orElse("n/a"));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD);
|
||||||
// after security filter, so to be able to log tenant
|
// after security filter, so to be able to log tenant
|
||||||
filterRegistrationBean.setOrder(securityProperties.getFilter().getOrder() + 1);
|
filterRegistrationBean.setOrder(securityFilterProperties.getOrder() + 1);
|
||||||
return filterRegistrationBean;
|
return filterRegistrationBean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoConfiguration(afterName = "org.eclipse.hawkbit.autoconfigure.security.SecurityAutoConfiguration")
|
@AutoConfiguration(afterName = "org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration")
|
||||||
|
@ConditionalOnClass(name = "org.springframework.boot.data.metrics.DefaultRepositoryTagsProvider")
|
||||||
@ConditionalOnProperty(name = "hawkbit.metrics.tenancy.repository.enabled", havingValue = "true", matchIfMissing = true)
|
@ConditionalOnProperty(name = "hawkbit.metrics.tenancy.repository.enabled", havingValue = "true", matchIfMissing = true)
|
||||||
@ConditionalOnClass(name = {
|
|
||||||
"io.micrometer.core.instrument.Tag",
|
|
||||||
"org.springframework.data.repository.core.support.RepositoryMethodInvocationListener" })
|
|
||||||
public static class RepositoryConfig {
|
public static class RepositoryConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RepositoryTagsProvider repositoryTagsProvider() {
|
public RepositoryTagsProvider repositoryTagsProvider() {
|
||||||
return new DefaultRepositoryTagsProvider() {
|
return new DefaultRepositoryTagsProvider() {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Iterable<Tag> repositoryTags(final RepositoryMethodInvocationListener.RepositoryMethodInvocation invocation) {
|
public Iterable<Tag> repositoryTags(@NonNull final RepositoryMethodInvocationListener.RepositoryMethodInvocation invocation) {
|
||||||
final Iterable<Tag> defaultTags = super.repositoryTags(invocation);
|
final Iterable<Tag> defaultTags = super.repositoryTags(invocation);
|
||||||
final String tenant = TENANT_TAG_VALUE_PROVIDER.get();
|
final String tenant = TENANT_TAG_VALUE_PROVIDER.get();
|
||||||
return () -> {
|
return () -> {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import org.springframework.cache.caffeine.CaffeineCache;
|
|||||||
import org.springframework.cache.support.AbstractValueAdaptingCache;
|
import org.springframework.cache.support.AbstractValueAdaptingCache;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.lang.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A spring Cache Manager that handles the multi tenancy.
|
* A spring Cache Manager that handles the multi tenancy.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
org.eclipse.hawkbit.HawkbitAutoConfiguration
|
||||||
org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration
|
org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration
|
||||||
org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration.WebConfig
|
org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration.WebConfig
|
||||||
org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration.RepositoryConfig
|
org.eclipse.hawkbit.tenancy.DefaultTenantConfiguration.RepositoryConfig
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||||
|
#
|
||||||
|
# This program and the accompanying materials are made
|
||||||
|
# available under the terms of the Eclipse Public License 2.0
|
||||||
|
# which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EPL-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
# sets MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS to true
|
||||||
|
spring.jackson.mapper.allow-final-fields-as-mutators=true
|
||||||
|
# sets DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY to true
|
||||||
|
# this feature allow sending single value instead of array of single value for array fields.
|
||||||
|
spring.jackson.deserialization.accept-single-value-as-array=true
|
||||||
@@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.lang.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
<groupId>tools.jackson.dataformat</groupId>
|
||||||
<artifactId>jackson-dataformat-cbor</artifactId>
|
<artifactId>jackson-dataformat-cbor</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -64,5 +64,11 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webmvc-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -18,20 +18,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonFactory;
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
|
|
||||||
import com.fasterxml.jackson.dataformat.cbor.CBORGenerator;
|
|
||||||
import com.fasterxml.jackson.dataformat.cbor.CBORParser;
|
|
||||||
import org.eclipse.hawkbit.context.AccessContext;
|
import org.eclipse.hawkbit.context.AccessContext;
|
||||||
import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback;
|
import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback;
|
||||||
import org.eclipse.hawkbit.ddi.json.model.DdiAssignedVersion;
|
import org.eclipse.hawkbit.ddi.json.model.DdiAssignedVersion;
|
||||||
@@ -54,6 +45,11 @@ import org.springframework.test.context.TestPropertySource;
|
|||||||
import org.springframework.test.web.servlet.ResultActions;
|
import org.springframework.test.web.servlet.ResultActions;
|
||||||
import org.springframework.test.web.servlet.ResultMatcher;
|
import org.springframework.test.web.servlet.ResultMatcher;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
import tools.jackson.core.JsonGenerator;
|
||||||
|
import tools.jackson.core.JsonParser;
|
||||||
|
import tools.jackson.core.json.JsonFactory;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
import tools.jackson.dataformat.cbor.CBORFactory;
|
||||||
|
|
||||||
@ContextConfiguration(
|
@ContextConfiguration(
|
||||||
classes = { DdiApiConfiguration.class, RestConfiguration.class, JpaRepositoryConfiguration.class, TestConfiguration.class })
|
classes = { DdiApiConfiguration.class, RestConfiguration.class, JpaRepositoryConfiguration.class, TestConfiguration.class })
|
||||||
@@ -86,14 +82,13 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
|
|||||||
*
|
*
|
||||||
* @param json JSON object to convert
|
* @param json JSON object to convert
|
||||||
* @return Equivalent CBOR data
|
* @return Equivalent CBOR data
|
||||||
* @throws IOException Invalid JSON input
|
|
||||||
*/
|
*/
|
||||||
protected static byte[] jsonToCbor(final String json) throws IOException {
|
protected static byte[] jsonToCbor(final String json) {
|
||||||
final JsonFactory jsonFactory = new JsonFactory();
|
final JsonFactory jsonFactory = new JsonFactory();
|
||||||
final JsonParser jsonParser = jsonFactory.createParser(json);
|
final JsonParser jsonParser = jsonFactory.createParser(json);
|
||||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
final CBORFactory cborFactory = new CBORFactory();
|
final CBORFactory cborFactory = new CBORFactory();
|
||||||
final CBORGenerator cborGenerator = cborFactory.createGenerator(out);
|
final JsonGenerator cborGenerator = cborFactory.createGenerator(out);
|
||||||
while (jsonParser.nextToken() != null) {
|
while (jsonParser.nextToken() != null) {
|
||||||
cborGenerator.copyCurrentEvent(jsonParser);
|
cborGenerator.copyCurrentEvent(jsonParser);
|
||||||
}
|
}
|
||||||
@@ -106,11 +101,9 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
|
|||||||
*
|
*
|
||||||
* @param input CBOR data to convert
|
* @param input CBOR data to convert
|
||||||
* @return Equivalent JSON string
|
* @return Equivalent JSON string
|
||||||
* @throws IOException Invalid CBOR input
|
|
||||||
*/
|
*/
|
||||||
protected static String cborToJson(final byte[] input) throws IOException {
|
protected static String cborToJson(final byte[] input) {
|
||||||
final CBORFactory cborFactory = new CBORFactory();
|
final JsonParser cborParser = new CBORFactory().createParser(input);
|
||||||
final CBORParser cborParser = cborFactory.createParser(input);
|
|
||||||
final JsonFactory jsonFactory = new JsonFactory();
|
final JsonFactory jsonFactory = new JsonFactory();
|
||||||
final StringWriter stringWriter = new StringWriter();
|
final StringWriter stringWriter = new StringWriter();
|
||||||
final JsonGenerator jsonGenerator = jsonFactory.createGenerator(stringWriter);
|
final JsonGenerator jsonGenerator = jsonFactory.createGenerator(stringWriter);
|
||||||
@@ -210,107 +203,92 @@ public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrat
|
|||||||
controllerId + "/deploymentBase/" + actionId;
|
controllerId + "/deploymentBase/" + actionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonRejectedCancelActionFeedback() throws JsonProcessingException {
|
protected String getJsonRejectedCancelActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("rejected"));
|
||||||
DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("rejected"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonRejectedDeploymentActionFeedback() throws JsonProcessingException {
|
protected String getJsonRejectedDeploymentActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.NONE, Collections.singletonList("rejected"));
|
||||||
DdiStatus.ExecutionStatus.REJECTED, DdiResult.FinalResult.NONE, Collections.singletonList("rejected"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonDownloadDeploymentActionFeedback() throws JsonProcessingException {
|
protected String getJsonDownloadDeploymentActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.DOWNLOAD, DdiResult.FinalResult.NONE, Collections.singletonList("download"));
|
||||||
DdiStatus.ExecutionStatus.DOWNLOAD, DdiResult.FinalResult.NONE, Collections.singletonList("download"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonDownloadedDeploymentActionFeedback() throws JsonProcessingException {
|
protected String getJsonDownloadedDeploymentActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.DOWNLOADED, DdiResult.FinalResult.NONE, Collections.singletonList("download"));
|
||||||
DdiStatus.ExecutionStatus.DOWNLOADED, DdiResult.FinalResult.NONE, Collections.singletonList("download"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonCanceledCancelActionFeedback() throws JsonProcessingException {
|
protected String getJsonCanceledCancelActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("canceled"));
|
||||||
DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("canceled"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonCanceledDeploymentActionFeedback() throws JsonProcessingException {
|
protected String getJsonCanceledDeploymentActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.NONE, Collections.singletonList("canceled"));
|
||||||
DdiStatus.ExecutionStatus.CANCELED, DdiResult.FinalResult.NONE, Collections.singletonList("canceled"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonScheduledCancelActionFeedback() throws JsonProcessingException {
|
protected String getJsonScheduledCancelActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.SUCCESS,
|
||||||
DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("scheduled"));
|
Collections.singletonList("scheduled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonScheduledDeploymentActionFeedback() throws JsonProcessingException {
|
protected String getJsonScheduledDeploymentActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.NONE, Collections.singletonList("scheduled"));
|
||||||
DdiStatus.ExecutionStatus.SCHEDULED, DdiResult.FinalResult.NONE, Collections.singletonList("scheduled"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonResumedCancelActionFeedback() throws JsonProcessingException {
|
protected String getJsonResumedCancelActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("resumed"));
|
||||||
DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("resumed"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonResumedDeploymentActionFeedback() throws JsonProcessingException {
|
protected String getJsonResumedDeploymentActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.NONE, Collections.singletonList("resumed"));
|
||||||
DdiStatus.ExecutionStatus.RESUMED, DdiResult.FinalResult.NONE, Collections.singletonList("resumed"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonProceedingCancelActionFeedback() throws JsonProcessingException {
|
protected String getJsonProceedingCancelActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(
|
||||||
DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.SUCCESS, Collections.singletonList("proceeding"));
|
DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.SUCCESS, Collections.singletonList("proceeding"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonProceedingDeploymentActionFeedback() throws JsonProcessingException {
|
protected String getJsonProceedingDeploymentActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE, Collections.singletonList("proceeding"));
|
||||||
DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE, Collections.singletonList("proceeding"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonClosedCancelActionFeedback() throws JsonProcessingException {
|
protected String getJsonClosedCancelActionFeedback() {
|
||||||
return getJsonActionFeedback(
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("closed"));
|
||||||
DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.SUCCESS, Collections.singletonList("closed"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonClosedDeploymentActionFeedback() throws JsonProcessingException {
|
protected String getJsonClosedDeploymentActionFeedback() {
|
||||||
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE, Collections.singletonList("closed"));
|
return getJsonActionFeedback(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.NONE, Collections.singletonList("closed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonActionFeedback(
|
protected String getJsonActionFeedback(final DdiStatus.ExecutionStatus executionStatus, final DdiResult.FinalResult finalResult) {
|
||||||
final DdiStatus.ExecutionStatus executionStatus, final DdiResult.FinalResult finalResult) throws JsonProcessingException {
|
|
||||||
return getJsonActionFeedback(executionStatus, finalResult, Collections.singletonList(randomString(1000)));
|
return getJsonActionFeedback(executionStatus, finalResult, Collections.singletonList(randomString(1000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonActionFeedback(
|
protected String getJsonActionFeedback(
|
||||||
final DdiStatus.ExecutionStatus executionStatus, final DdiResult ddiResult,
|
final DdiStatus.ExecutionStatus executionStatus, final DdiResult ddiResult, final List<String> messages) {
|
||||||
final List<String> messages) throws JsonProcessingException {
|
|
||||||
final DdiStatus ddiStatus = new DdiStatus(executionStatus, ddiResult, null, messages);
|
final DdiStatus ddiStatus = new DdiStatus(executionStatus, ddiResult, null, messages);
|
||||||
return OBJECT_MAPPER.writeValueAsString(new DdiActionFeedback(ddiStatus));
|
return OBJECT_MAPPER.writeValueAsString(new DdiActionFeedback(ddiStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonActionFeedback(
|
protected String getJsonActionFeedback(
|
||||||
final DdiStatus.ExecutionStatus executionStatus,
|
final DdiStatus.ExecutionStatus executionStatus, final DdiResult.FinalResult finalResult, final List<String> messages) {
|
||||||
final DdiResult.FinalResult finalResult, final List<String> messages) throws JsonProcessingException {
|
|
||||||
return getJsonActionFeedback(executionStatus, finalResult, null, messages);
|
return getJsonActionFeedback(executionStatus, finalResult, null, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonActionFeedback(
|
protected String getJsonActionFeedback(
|
||||||
final DdiStatus.ExecutionStatus executionStatus,
|
final DdiStatus.ExecutionStatus executionStatus,
|
||||||
final DdiResult.FinalResult finalResult, final Integer code, final List<String> messages) throws JsonProcessingException {
|
final DdiResult.FinalResult finalResult, final Integer code, final List<String> messages) {
|
||||||
final DdiStatus ddiStatus = new DdiStatus(executionStatus, new DdiResult(finalResult, new DdiProgress(2, 5)), code, messages);
|
final DdiStatus ddiStatus = new DdiStatus(executionStatus, new DdiResult(finalResult, new DdiProgress(2, 5)), code, messages);
|
||||||
return OBJECT_MAPPER.writeValueAsString(new DdiActionFeedback(ddiStatus));
|
return OBJECT_MAPPER.writeValueAsString(new DdiActionFeedback(ddiStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonConfirmationFeedback(
|
protected String getJsonConfirmationFeedback(
|
||||||
final DdiConfirmationFeedback.Confirmation confirmation,
|
final DdiConfirmationFeedback.Confirmation confirmation, final Integer code, final List<String> messages) {
|
||||||
final Integer code, final List<String> messages) throws JsonProcessingException {
|
|
||||||
return OBJECT_MAPPER.writeValueAsString(new DdiConfirmationFeedback(confirmation, code, messages));
|
return OBJECT_MAPPER.writeValueAsString(new DdiConfirmationFeedback(confirmation, code, messages));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getJsonInstalledBase(String name, String version) throws JsonProcessingException {
|
protected String getJsonInstalledBase(final String name, final String version) {
|
||||||
return OBJECT_MAPPER.writeValueAsString(new DdiAssignedVersion(name, version));
|
return OBJECT_MAPPER.writeValueAsString(new DdiAssignedVersion(name, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,11 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Database -->
|
<!-- Database -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
<!-- Spring - START -->
|
<!-- Spring - START -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class ControllerDownloadSecurityConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Order(300) // higher priority than HawkBit DDI security, so that the DDI DL security is applied first
|
@Order(300) // higher priority than HawkBit DDI security, so that the DDI DL security is applied first
|
||||||
protected SecurityFilterChain filterChainDDIDL(final HttpSecurity http) throws Exception {
|
protected SecurityFilterChain filterChainDDIDL(final HttpSecurity http) {
|
||||||
http
|
http
|
||||||
.securityMatcher(DDI_DL_ANT_MATCHER)
|
.securityMatcher(DDI_DL_ANT_MATCHER)
|
||||||
.authorizeHttpRequests(amrmRegistry -> amrmRegistry.anyRequest().authenticated())
|
.authorizeHttpRequests(amrmRegistry -> amrmRegistry.anyRequest().authenticated())
|
||||||
|
|||||||
@@ -40,11 +40,7 @@
|
|||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.amqp</groupId>
|
|
||||||
<artifactId>spring-rabbit</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
|
|
||||||
protected void sendPingResponseToDmfReceiver(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
|
final Message message = MessageBuilder
|
||||||
.withBody(String.valueOf(java.lang.System.currentTimeMillis()).getBytes())
|
.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.TYPE, MessageType.PING_RESPONSE)
|
||||||
@@ -457,7 +457,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
// due to the fact that all targets in a batch use the same set of software modules we don't generate target-specific urls
|
// due to the fact that all targets in a batch use the same set of software modules we don't generate target-specific urls
|
||||||
final Target firstTarget = targets.get(0);
|
final Target firstTarget = targets.get(0);
|
||||||
final DmfBatchDownloadAndUpdateRequest batchRequest = new DmfBatchDownloadAndUpdateRequest(
|
final DmfBatchDownloadAndUpdateRequest batchRequest = new DmfBatchDownloadAndUpdateRequest(
|
||||||
java.lang.System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
dmfTargets,
|
dmfTargets,
|
||||||
Optional.ofNullable(modules)
|
Optional.ofNullable(modules)
|
||||||
.map(Map::entrySet)
|
.map(Map::entrySet)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
package org.eclipse.hawkbit.amqp;
|
package org.eclipse.hawkbit.amqp;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -32,9 +33,9 @@ import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler
|
|||||||
import org.springframework.amqp.rabbit.listener.FatalExceptionStrategy;
|
import org.springframework.amqp.rabbit.listener.FatalExceptionStrategy;
|
||||||
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
|
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
|
||||||
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
|
import org.springframework.amqp.support.converter.JacksonJsonMessageConverter;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
|
import org.springframework.boot.amqp.autoconfigure.SimpleRabbitListenerContainerFactoryConfigurer;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
@@ -42,9 +43,10 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
|
import org.springframework.core.retry.RetryPolicy;
|
||||||
import org.springframework.retry.support.RetryTemplate;
|
import org.springframework.core.retry.RetryTemplate;
|
||||||
import org.springframework.util.ErrorHandler;
|
import org.springframework.util.ErrorHandler;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring configuration for AMQP based DMF communication for indirect device integration.
|
* Spring configuration for AMQP based DMF communication for indirect device integration.
|
||||||
@@ -91,13 +93,16 @@ public class DmfApiConfiguration {
|
|||||||
* @return {@link RabbitTemplate} with automatic retry, published confirms and {@link Jackson2JsonMessageConverter}.
|
* @return {@link RabbitTemplate} with automatic retry, published confirms and {@link Jackson2JsonMessageConverter}.
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public RabbitTemplate rabbitTemplate() {
|
public RabbitTemplate rabbitTemplate(final JsonMapper jsonMapper) {
|
||||||
final RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory);
|
final RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory);
|
||||||
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
|
rabbitTemplate.setMessageConverter(new JacksonJsonMessageConverter(jsonMapper));
|
||||||
|
|
||||||
final RetryTemplate retryTemplate = new RetryTemplate();
|
// the same policy the previously used default ExponentialBackOffPolicy applied
|
||||||
retryTemplate.setBackOffPolicy(new ExponentialBackOffPolicy());
|
rabbitTemplate.setRetryTemplate(new RetryTemplate(RetryPolicy.builder()
|
||||||
rabbitTemplate.setRetryTemplate(retryTemplate);
|
.delay(Duration.ofMillis(100))
|
||||||
|
.multiplier(2)
|
||||||
|
.maxDelay(Duration.ofSeconds(30))
|
||||||
|
.build()));
|
||||||
|
|
||||||
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
|
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
|
||||||
if (ack) {
|
if (ack) {
|
||||||
@@ -136,8 +141,8 @@ public class DmfApiConfiguration {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public AmqpMessageSenderService amqpSenderServiceBean() {
|
public AmqpMessageSenderService amqpSenderServiceBean(final RabbitTemplate rabbitTemplate) {
|
||||||
return new DefaultAmqpMessageSenderService(rabbitTemplate());
|
return new DefaultAmqpMessageSenderService(rabbitTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,5 +208,4 @@ public class DmfApiConfiguration {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ import org.springframework.amqp.AmqpRejectAndDontRequeueException;
|
|||||||
import org.springframework.amqp.core.Message;
|
import org.springframework.amqp.core.Message;
|
||||||
import org.springframework.amqp.core.MessageProperties;
|
import org.springframework.amqp.core.MessageProperties;
|
||||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
|
import org.springframework.amqp.support.converter.JacksonJsonMessageConverter;
|
||||||
import org.springframework.amqp.support.converter.MessageConversionException;
|
import org.springframework.amqp.support.converter.MessageConversionException;
|
||||||
import org.springframework.amqp.support.converter.MessageConverter;
|
import org.springframework.amqp.support.converter.MessageConverter;
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ class AmqpMessageHandlerServiceTest {
|
|||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
void before() {
|
void before() {
|
||||||
TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagement);
|
TenantConfigHelper.setTenantConfigurationManagement(tenantConfigurationManagement);
|
||||||
messageConverter = new Jackson2JsonMessageConverter();
|
messageConverter = new JacksonJsonMessageConverter();
|
||||||
lenient().when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter);
|
lenient().when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter);
|
||||||
|
|
||||||
amqpMessageHandlerService = new AmqpMessageHandlerService(
|
amqpMessageHandlerService = new AmqpMessageHandlerService(
|
||||||
|
|||||||
@@ -751,7 +751,6 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
|
|||||||
// retrieve action and ensure that it is in Running state
|
// retrieve action and ensure that it is in Running state
|
||||||
final Action action = deploymentManagement.findAction(actionId).orElseThrow(() -> new AssertionError("Action not found!"));
|
final Action action = deploymentManagement.findAction(actionId).orElseThrow(() -> new AssertionError("Action not found!"));
|
||||||
assertThat(action.getStatus()).isEqualTo(Status.RUNNING);
|
assertThat(action.getStatus()).isEqualTo(Status.RUNNING);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
2
hawkbit-dmf/hawkbit-dmf-api/lombok.config
Normal file
2
hawkbit-dmf/hawkbit-dmf-api/lombok.config
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Disable nullability annotations in order to do not bring jspecify as a dependency
|
||||||
|
lombok.addNullAnnotations=none
|
||||||
@@ -52,18 +52,11 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.rabbitmq</groupId>
|
<groupId>com.rabbitmq</groupId>
|
||||||
<artifactId>http-client</artifactId>
|
<artifactId>http-client</artifactId>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.amqp</groupId>
|
|
||||||
<artifactId>spring-rabbit-test</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.hawkbit</groupId>
|
<groupId>org.eclipse.hawkbit</groupId>
|
||||||
<artifactId>hawkbit-repository-test</artifactId>
|
<artifactId>hawkbit-repository-test</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.awaitility</groupId>
|
<groupId>org.awaitility</groupId>
|
||||||
|
|||||||
@@ -45,11 +45,6 @@
|
|||||||
<groupId>org.mariadb.jdbc</groupId>
|
<groupId>org.mariadb.jdbc</groupId>
|
||||||
<artifactId>mariadb-java-client</artifactId>
|
<artifactId>mariadb-java-client</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.servlet</groupId>
|
|
||||||
<artifactId>jakarta.servlet-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.mcp.server;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
|
import org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standalone MCP Server application that connects to hawkBit via REST API.
|
* Standalone MCP Server application that connects to hawkBit via REST API.
|
||||||
|
|||||||
@@ -31,5 +31,11 @@
|
|||||||
<artifactId>hawkbit-rest-api</artifactId>
|
<artifactId>hawkbit-rest-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-hateoas-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||||
@@ -17,6 +18,7 @@ import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
|||||||
/**
|
/**
|
||||||
* Request Body of DistributionSet for assignment operations (ID only).
|
* Request Body of DistributionSet for assignment operations (ID only).
|
||||||
*/
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
|||||||
@@ -41,13 +41,11 @@ class MgmtTargetAssignmentResponseBodyTest {
|
|||||||
|
|
||||||
assertThat(jsonNode.has("assigned")).as("the assigned targets count").isTrue();
|
assertThat(jsonNode.has("assigned")).as("the assigned targets count").isTrue();
|
||||||
assertThat(jsonNode.get("assigned").isNumber()).as("the assigned targets count").isTrue();
|
assertThat(jsonNode.get("assigned").isNumber()).as("the assigned targets count").isTrue();
|
||||||
assertThat(jsonNode.get("assigned").asLong()).as("the assigned targets count")
|
assertThat(jsonNode.get("assigned").asLong()).as("the assigned targets count").isEqualTo(ASSIGNED_ACTIONS.size());
|
||||||
.isEqualTo(ASSIGNED_ACTIONS.size());
|
|
||||||
|
|
||||||
assertThat(jsonNode.has("alreadyAssigned")).as("the already assigned targets count").isTrue();
|
assertThat(jsonNode.has("alreadyAssigned")).as("the already assigned targets count").isTrue();
|
||||||
assertThat(jsonNode.get("alreadyAssigned").isNumber()).as("the already assigned targets count").isTrue();
|
assertThat(jsonNode.get("alreadyAssigned").isNumber()).as("the already assigned targets count").isTrue();
|
||||||
assertThat(jsonNode.get("alreadyAssigned").asLong()).as("the already assigned targets count")
|
assertThat(jsonNode.get("alreadyAssigned").asLong()).as("the already assigned targets count").isEqualTo(ALREADY_ASSIGNED_COUNT);
|
||||||
.isEqualTo(ALREADY_ASSIGNED_COUNT);
|
|
||||||
|
|
||||||
assertThat(jsonNode.has("total")).as("the total targets count").isTrue();
|
assertThat(jsonNode.has("total")).as("the total targets count").isTrue();
|
||||||
assertThat(jsonNode.get("total").isNumber()).as("the total targets count").isTrue();
|
assertThat(jsonNode.get("total").isNumber()).as("the total targets count").isTrue();
|
||||||
|
|||||||
@@ -59,5 +59,11 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webmvc-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -17,6 +17,7 @@ import org.springframework.context.annotation.Import;
|
|||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable {@link ComponentScan} in the resource package to set up all {@link Controller} annotated classes and set up the REST-Resources
|
* Enable {@link ComponentScan} in the resource package to set up all {@link Controller} annotated classes and set up the REST-Resources
|
||||||
@@ -27,4 +28,4 @@ import org.springframework.stereotype.Controller;
|
|||||||
@ComponentScan
|
@ComponentScan
|
||||||
@Import({ RestConfiguration.class, OpenApi.class })
|
@Import({ RestConfiguration.class, OpenApi.class })
|
||||||
@PropertySource("classpath:/hawkbit-mgmt-api-defaults.properties")
|
@PropertySource("classpath:/hawkbit-mgmt-api-defaults.properties")
|
||||||
public class MgmtApiConfiguration {}
|
public class MgmtApiConfiguration implements WebMvcConfigurer {}
|
||||||
@@ -32,8 +32,8 @@ import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||||
import org.springframework.hateoas.MediaTypes;
|
import org.springframework.hateoas.MediaTypes;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
import org.springframework.boot.jpa.autoconfigure.JpaProperties;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Slice;
|
import org.springframework.data.domain.Slice;
|
||||||
@@ -145,8 +145,6 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
ActionRepository actionRepository;
|
ActionRepository actionRepository;
|
||||||
@Autowired
|
@Autowired
|
||||||
private JpaProperties jpaProperties;
|
private JpaProperties jpaProperties;
|
||||||
@Autowired
|
|
||||||
private ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that when targetType value of -1 is provided the target type is unassigned from the target.
|
* Ensures that when targetType value of -1 is provided the target type is unassigned from the target.
|
||||||
@@ -254,7 +252,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
final MgmtTargetAutoConfirmUpdate body = new MgmtTargetAutoConfirmUpdate("custom_initiator_value", "custom_remark_value");
|
final MgmtTargetAutoConfirmUpdate body = new MgmtTargetAutoConfirmUpdate("custom_initiator_value", "custom_remark_value");
|
||||||
mvc.perform(post(TARGETS_V1 + "/{targetId}/" + AUTO_CONFIRM + "/" + ACTIVATE,
|
mvc.perform(post(TARGETS_V1 + "/{targetId}/" + AUTO_CONFIRM + "/" + ACTIVATE,
|
||||||
testTarget.getControllerId())
|
testTarget.getControllerId())
|
||||||
.content(objectMapper.writeValueAsString(body)).contentType(APPLICATION_JSON))
|
.content(OBJECT_MAPPER.writeValueAsString(body)).contentType(APPLICATION_JSON))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isNoContent());
|
.andExpect(status().isNoContent());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -571,13 +571,13 @@ class MgmtTargetTypeResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isNotFound());
|
.andExpect(status().isNotFound());
|
||||||
|
|
||||||
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).content("{\"id\":1}")
|
// actually it is semi invalid could become bad request - not strict but yet accepted
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
// single element is assumed to be array of single element see {@link MgmtApiConfiguration#configureMessageConverters}
|
||||||
|
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).contentType(MediaType.APPLICATION_JSON).content("{\"id\":44456}"))
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isBadRequest());
|
.andExpect(status().isNotFound());
|
||||||
|
|
||||||
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).content("[{\"id\":44456}]")
|
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).contentType(MediaType.APPLICATION_JSON).content("[{\"id\":44456}]"))
|
||||||
.contentType(MediaType.APPLICATION_JSON))
|
|
||||||
.andDo(MockMvcResultPrinter.print())
|
.andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(status().isNotFound());
|
.andExpect(status().isNotFound());
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,11 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Database -->
|
<!-- Database -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import java.util.Map;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
import org.springframework.boot.autoconfigure.web.WebProperties;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
|
import org.springframework.boot.webmvc.autoconfigure.error.BasicErrorController;
|
||||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
import org.springframework.boot.webmvc.error.ErrorAttributes;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@@ -38,10 +38,10 @@ public class ErrorController extends BasicErrorController {
|
|||||||
* A new {@link ErrorController}.
|
* A new {@link ErrorController}.
|
||||||
*
|
*
|
||||||
* @param errorAttributes the error attributes
|
* @param errorAttributes the error attributes
|
||||||
* @param serverProperties configuration properties
|
* @param webProperties web configuration properties
|
||||||
*/
|
*/
|
||||||
public ErrorController(final ErrorAttributes errorAttributes, final ServerProperties serverProperties) {
|
public ErrorController(final ErrorAttributes errorAttributes, final WebProperties webProperties) {
|
||||||
super(errorAttributes, serverProperties.getError());
|
super(errorAttributes, webProperties.getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
@RequestMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.app.mgmt;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
@@ -59,11 +60,13 @@ class CorsTest extends AbstractSecurityTest {
|
|||||||
.getContentAsString();
|
.getContentAsString();
|
||||||
assertThat(invalidOriginResponseBody).isEqualTo(INVALID_CORS_REQUEST);
|
assertThat(invalidOriginResponseBody).isEqualTo(INVALID_CORS_REQUEST);
|
||||||
|
|
||||||
final String invalidCorsUrlResponseBody = performOptionsRequestToUrlWithOrigin(
|
performOptionsRequestToUrlWithOrigin("/some_uri", ALLOWED_ORIGIN_FIRST)
|
||||||
"/some_uri", ALLOWED_ORIGIN_FIRST).andExpect(status().isForbidden())
|
// TODO (Spring Boot 4 Migration): Since 4.0 at lest test returns 200 for not found - not going via CORS
|
||||||
|
// before it was 403 + INVALID_CORS_REQUEST
|
||||||
|
// .andExpect(status().isForbidden()).andExpect(content().string(INVALID_CORS_REQUEST)) // Spring Boot 3
|
||||||
|
.andExpect(content().string(""))
|
||||||
.andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).andReturn()
|
.andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).andReturn()
|
||||||
.getResponse().getContentAsString();
|
.getResponse().getContentAsString();
|
||||||
assertThat(invalidCorsUrlResponseBody).isEqualTo(INVALID_CORS_REQUEST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResultActions performOptionsRequestToRestWithOrigin(final String origin) throws Exception {
|
private ResultActions performOptionsRequestToRestWithOrigin(final String origin) throws Exception {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
<!-- Spring - START -->
|
<!-- Spring - START -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ public class MgmtSecurityConfiguration {
|
|||||||
// could be used for instance to set authentication provider
|
// could be used for instance to set authentication provider
|
||||||
// Note: implementation of the customizer shall always take in account what is the already set by the hawkBit
|
// Note: implementation of the customizer shall always take in account what is the already set by the hawkBit
|
||||||
@Autowired(required = false) @Qualifier("hawkbitHttpSecurityCustomizer") final Customizer<HttpSecurity> httpSecurityCustomizer,
|
@Autowired(required = false) @Qualifier("hawkbitHttpSecurityCustomizer") final Customizer<HttpSecurity> httpSecurityCustomizer,
|
||||||
final SystemManagement systemManagement) throws Exception {
|
final SystemManagement systemManagement) {
|
||||||
http
|
http
|
||||||
.securityMatcher(MgmtRestConstants.REST + "/**")
|
.securityMatcher(MgmtRestConstants.REST + "/**")
|
||||||
.authorizeHttpRequests(amrmRegistry -> amrmRegistry
|
.authorizeHttpRequests(amrmRegistry -> amrmRegistry
|
||||||
|
|||||||
@@ -32,6 +32,11 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Database -->
|
<!-- Database -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
@@ -58,9 +63,14 @@
|
|||||||
<!-- Database END -->
|
<!-- Database END -->
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.springframework.security</groupId>-->
|
||||||
|
<!-- <artifactId>spring-security-test</artifactId>-->
|
||||||
|
<!-- <scope>test</scope>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-security-test</artifactId>
|
<artifactId>spring-boot-starter-security-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import java.util.Map;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
import org.springframework.boot.autoconfigure.web.WebProperties;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
|
import org.springframework.boot.webmvc.autoconfigure.error.BasicErrorController;
|
||||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
import org.springframework.boot.webmvc.error.ErrorAttributes;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@@ -38,10 +38,10 @@ public class ErrorController extends BasicErrorController {
|
|||||||
* A new {@link ErrorController}.
|
* A new {@link ErrorController}.
|
||||||
*
|
*
|
||||||
* @param errorAttributes the error attributes
|
* @param errorAttributes the error attributes
|
||||||
* @param serverProperties configuration properties
|
* @param webProperties web configuration properties
|
||||||
*/
|
*/
|
||||||
public ErrorController(final ErrorAttributes errorAttributes, final ServerProperties serverProperties) {
|
public ErrorController(final ErrorAttributes errorAttributes, final WebProperties webProperties) {
|
||||||
super(errorAttributes, serverProperties.getError());
|
super(errorAttributes, webProperties.getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
@RequestMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.app;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
@@ -59,11 +60,13 @@ class CorsTest extends AbstractSecurityTest {
|
|||||||
.getContentAsString();
|
.getContentAsString();
|
||||||
assertThat(invalidOriginResponseBody).isEqualTo(INVALID_CORS_REQUEST);
|
assertThat(invalidOriginResponseBody).isEqualTo(INVALID_CORS_REQUEST);
|
||||||
|
|
||||||
final String invalidCorsUrlResponseBody = performOptionsRequestToUrlWithOrigin(
|
performOptionsRequestToUrlWithOrigin("/some_uri", ALLOWED_ORIGIN_FIRST)
|
||||||
"/some_uri", ALLOWED_ORIGIN_FIRST).andExpect(status().isForbidden())
|
// TODO (Spring Boot 4 Migration): Since 4.0 at lest test returns 200 for not found - not going via CORS
|
||||||
|
// before it was 403 + INVALID_CORS_REQUEST
|
||||||
|
// .andExpect(status().isForbidden()).andExpect(content().string(INVALID_CORS_REQUEST)) // Spring Boot 3
|
||||||
|
.andExpect(content().string(""))
|
||||||
.andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).andReturn()
|
.andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).andReturn()
|
||||||
.getResponse().getContentAsString();
|
.getResponse().getContentAsString();
|
||||||
assertThat(invalidCorsUrlResponseBody).isEqualTo(INVALID_CORS_REQUEST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResultActions performOptionsRequestToRestWithOrigin(final String origin) throws Exception {
|
private ResultActions performOptionsRequestToRestWithOrigin(final String origin) throws Exception {
|
||||||
|
|||||||
@@ -22,6 +22,11 @@
|
|||||||
<name>hawkBit :: Query Language :: JPA</name>
|
<name>hawkBit :: Query Language :: JPA</name>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.persistence</groupId>
|
||||||
|
<artifactId>jakarta.persistence-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.persistence</groupId>
|
<groupId>org.eclipse.persistence</groupId>
|
||||||
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
||||||
@@ -34,19 +39,9 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.persistence</groupId>
|
|
||||||
<artifactId>jakarta.persistence-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.hibernate.orm</groupId>
|
|
||||||
<artifactId>hibernate-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -56,6 +51,11 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
import org.hibernate.query.sqm.internal.QuerySqmImpl;
|
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||||
|
import org.hibernate.query.sqm.internal.SqmQueryImpl;
|
||||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||||
import org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess;
|
import org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess;
|
||||||
import org.hibernate.query.sqm.sql.SqmTranslation;
|
import org.hibernate.query.sqm.sql.SqmTranslation;
|
||||||
@@ -33,6 +35,7 @@ import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
|||||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
import org.hibernate.sql.ast.tree.MutationStatement;
|
import org.hibernate.sql.ast.tree.MutationStatement;
|
||||||
import org.hibernate.sql.ast.tree.Statement;
|
import org.hibernate.sql.ast.tree.Statement;
|
||||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||||
@@ -60,14 +63,14 @@ public class HibernateUtils {
|
|||||||
throw new UnsupportedOperationException("SqmTranslatorFactory resolver is not available");
|
throw new UnsupportedOperationException("SqmTranslatorFactory resolver is not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
final QuerySqmImpl<?> hqlQuery = query.unwrap(QuerySqmImpl.class);
|
final SqmQueryImpl<?> hqlQuery = query.unwrap(SqmQueryImpl.class);
|
||||||
final SessionFactoryImplementor factory = hqlQuery.getSessionFactory();
|
final SessionFactoryImplementor sessionFactory = hqlQuery.getSessionFactory();
|
||||||
final SharedSessionContractImplementor session = hqlQuery.getSession();
|
final SharedSessionContractImplementor session = hqlQuery.getSession();
|
||||||
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
final SqlAstCreationContext sqlAstCreationContext = (SqlAstCreationContext)session.getFactory();
|
||||||
|
|
||||||
final SqmTranslatorFactory sqmTranslatorFactory;
|
final SqmTranslatorFactory sqmTranslatorFactory;
|
||||||
try {
|
try {
|
||||||
sqmTranslatorFactory = (SqmTranslatorFactory) getSqmTranslatorFactory.invoke(factory.getQueryEngine());
|
sqmTranslatorFactory = (SqmTranslatorFactory) getSqmTranslatorFactory.invoke(sessionFactory.getQueryEngine());
|
||||||
} catch (final IllegalAccessException | InvocationTargetException e) {
|
} catch (final IllegalAccessException | InvocationTargetException e) {
|
||||||
throw new UnsupportedOperationException("Can't create SqmTranslatorFactory", e);
|
throw new UnsupportedOperationException("Can't create SqmTranslatorFactory", e);
|
||||||
}
|
}
|
||||||
@@ -76,19 +79,20 @@ public class HibernateUtils {
|
|||||||
hqlQuery.getSqmStatement() instanceof SqmSelectStatement<?> selectStatement
|
hqlQuery.getSqmStatement() instanceof SqmSelectStatement<?> selectStatement
|
||||||
? sqmTranslatorFactory.createSelectTranslator(selectStatement,
|
? sqmTranslatorFactory.createSelectTranslator(selectStatement,
|
||||||
hqlQuery.getQueryOptions(), hqlQuery.getDomainParameterXref(), hqlQuery.getQueryParameterBindings(),
|
hqlQuery.getQueryOptions(), hqlQuery.getDomainParameterXref(), hqlQuery.getQueryParameterBindings(),
|
||||||
hqlQuery.getLoadQueryInfluencers(), sessionFactory, false)
|
hqlQuery.getLoadQueryInfluencers(), sqlAstCreationContext, false)
|
||||||
: sqmTranslatorFactory.createMutationTranslator((SqmDmlStatement<?>) hqlQuery.getSqmStatement(),
|
: sqmTranslatorFactory.createMutationTranslator((SqmDmlStatement<?>) hqlQuery.getSqmStatement(),
|
||||||
hqlQuery.getQueryOptions(), hqlQuery.getDomainParameterXref(), hqlQuery.getQueryParameterBindings(),
|
hqlQuery.getQueryOptions(), hqlQuery.getDomainParameterXref(), hqlQuery.getQueryParameterBindings(),
|
||||||
hqlQuery.getLoadQueryInfluencers(), sessionFactory);
|
hqlQuery.getLoadQueryInfluencers(), sqlAstCreationContext);
|
||||||
|
|
||||||
final SqmTranslation<? extends Statement> sqmTranslation = sqmSelectTranslator.translate();
|
final SqmTranslation<? extends Statement> sqmTranslation = sqmSelectTranslator.translate();
|
||||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = factory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory();
|
final SqlAstTranslatorFactory sqlAstTranslatorFactory = sessionFactory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory();
|
||||||
final Map<QueryParameterImplementor<?>, Map<SqmParameter<?>, List<JdbcParametersList>>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref(
|
final Map<QueryParameterImplementor<?>, Map<SqmParameter<?>, List<JdbcParametersList>>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref(
|
||||||
hqlQuery.getDomainParameterXref(), sqmTranslation::getJdbcParamsBySqmParam);
|
hqlQuery.getDomainParameterXref(), sqmTranslation::getJdbcParamsBySqmParam);
|
||||||
|
|
||||||
final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(hqlQuery.getQueryParameterBindings(),
|
final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(
|
||||||
hqlQuery.getDomainParameterXref(), jdbcParamsXref, factory.getRuntimeMetamodels().getMappingMetamodel(),
|
(QueryParameterBindings) hqlQuery.getQueryParameterBindings(),
|
||||||
sqmSelectTranslator.getFromClauseAccess()::findTableGroup, new SqmParameterMappingModelResolutionAccess() {
|
(DomainParameterXref) hqlQuery.getDomainParameterXref(), jdbcParamsXref, /*sessionFactory.getRuntimeMetamodels().getMappingMetamodel(),
|
||||||
|
sqmSelectTranslator.getFromClauseAccess()::findTableGroup,*/ new SqmParameterMappingModelResolutionAccess() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@@ -97,9 +101,9 @@ public class HibernateUtils {
|
|||||||
}
|
}
|
||||||
}, hqlQuery.getSession());
|
}, hqlQuery.getSession());
|
||||||
return (sqmTranslation.getSqlAst() instanceof SelectStatement selectStatement
|
return (sqmTranslation.getSqlAst() instanceof SelectStatement selectStatement
|
||||||
? sqlAstTranslatorFactory.buildSelectTranslator(factory, selectStatement)
|
? sqlAstTranslatorFactory.buildSelectTranslator(sessionFactory, selectStatement)
|
||||||
.translate(jdbcParameterBindings, hqlQuery.getQueryOptions())
|
.translate(jdbcParameterBindings, hqlQuery.getQueryOptions())
|
||||||
: sqlAstTranslatorFactory.buildMutationTranslator(factory, (MutationStatement) sqmTranslation.getSqlAst())
|
: sqlAstTranslatorFactory.buildMutationTranslator(sessionFactory, (MutationStatement) sqmTranslation.getSqlAst())
|
||||||
.translate(jdbcParameterBindings, hqlQuery.getQueryOptions()))
|
.translate(jdbcParameterBindings, hqlQuery.getQueryOptions()))
|
||||||
.getSqlString();
|
.getSqlString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,11 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.SpringBootConfiguration;
|
import org.springframework.boot.SpringBootConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
|
||||||
@SuppressWarnings("java:S5961") // complex check because the matter is very complex
|
@SuppressWarnings("java:S5961") // complex check because the matter is very complex
|
||||||
@DataJpaTest(properties = { "spring.jpa.database=H2" }, excludeAutoConfiguration = { FlywayAutoConfiguration.class })
|
@DataJpaTest(properties = "spring.jpa.database=H2")
|
||||||
@EnableAutoConfiguration
|
@EnableAutoConfiguration
|
||||||
@Slf4j
|
@Slf4j
|
||||||
class SpecificationBuilderTest {
|
class SpecificationBuilderTest {
|
||||||
|
|||||||
@@ -34,9 +34,10 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>jackson-annotations</artifactId>
|
<artifactId>spring-data-commons</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.cronutils</groupId>
|
<groupId>com.cronutils</groupId>
|
||||||
<artifactId>cron-utils</artifactId>
|
<artifactId>cron-utils</artifactId>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Slice;
|
import org.springframework.data.domain.Slice;
|
||||||
import org.springframework.lang.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public abstract class AbstractRemoteEvent extends ApplicationEvent {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final String id;
|
private String id; // not a final - jackson 3 doesn't override finals
|
||||||
|
|
||||||
// for serialization libs like jackson
|
// for serialization libs like jackson
|
||||||
protected AbstractRemoteEvent() {
|
protected AbstractRemoteEvent() {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
|||||||
* Note: it implements {@link org.eclipse.hawkbit.tenancy.TenantAwareCacheManager.CacheEvictEvent} methods but in order
|
* Note: it implements {@link org.eclipse.hawkbit.tenancy.TenantAwareCacheManager.CacheEvictEvent} methods but in order
|
||||||
* to be really include in the cache eviction process the subclasses must declare that it implements that interface.
|
* to be really include in the cache eviction process the subclasses must declare that it implements that interface.
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true)
|
||||||
@Getter
|
@Getter
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@@ -34,13 +34,13 @@ public abstract class RemoteIdEvent extends RemoteTenantAwareEvent {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private Long entityId;
|
private final Long entityId;
|
||||||
private String entityClass;
|
private final String entityClass;
|
||||||
|
|
||||||
protected RemoteIdEvent(final String tenant, final Long entityId, final Class<? extends TenantAwareBaseEntity> entityClass) {
|
protected RemoteIdEvent(final String tenant, final Long entityId, final Class<? extends TenantAwareBaseEntity> entityClass) {
|
||||||
super(tenant, entityId);
|
super(tenant, entityId);
|
||||||
this.entityClass = entityClass.getName();
|
|
||||||
this.entityId = entityId;
|
this.entityId = entityId;
|
||||||
|
this.entityClass = entityClass.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCacheName() {
|
public String getCacheName() {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import org.eclipse.hawkbit.repository.event.TenantAwareEvent;
|
|||||||
* distributed events. All the necessary information of distributing events to
|
* distributed events. All the necessary information of distributing events to
|
||||||
* other nodes.
|
* other nodes.
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor(access = AccessLevel.PROTECTED) // for serialization libs like jackson
|
@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) // for serialization libs like jackson
|
||||||
@Getter
|
@Getter
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@@ -33,7 +33,7 @@ public class RemoteTenantAwareEvent extends AbstractRemoteEvent implements Tenan
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private String tenant;
|
private final String tenant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.springframework.lang.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the remote event of creating a new {@link Action}.
|
* Defines the remote event of creating a new {@link Action}.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
@@ -24,6 +25,7 @@ public class ActionCreatedEvent extends AbstractActionEvent implements EntityCre
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 2L;
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public ActionCreatedEvent(final Action action, final Long targetId, final Long rolloutId, final Long rolloutGroupId) {
|
public ActionCreatedEvent(final Action action, final Long targetId, final Long rolloutId, final Long rolloutGroupId) {
|
||||||
super(action, targetId, rolloutId, rolloutGroupId);
|
super(action, targetId, rolloutId, rolloutGroupId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
@@ -24,6 +25,7 @@ public class ActionUpdatedEvent extends AbstractActionEvent implements EntityUpd
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 2L;
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public ActionUpdatedEvent(final Action action, final Long targetId, final Long rolloutId, final Long rolloutGroupId) {
|
public ActionUpdatedEvent(final Action action, final Long targetId, final Long rolloutId, final Long rolloutGroupId) {
|
||||||
super(action, targetId, rolloutId, rolloutGroupId);
|
super(action, targetId, rolloutId, rolloutGroupId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
@@ -24,6 +25,7 @@ public class DistributionSetCreatedEvent extends RemoteEntityEvent<DistributionS
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public DistributionSetCreatedEvent(final DistributionSet distributionSet) {
|
public DistributionSetCreatedEvent(final DistributionSet distributionSet) {
|
||||||
super(distributionSet);
|
super(distributionSet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||||
@@ -24,6 +25,7 @@ public class DistributionSetTagCreatedEvent extends RemoteEntityEvent<Distributi
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public DistributionSetTagCreatedEvent(final DistributionSetTag distributionSetTag) {
|
public DistributionSetTagCreatedEvent(final DistributionSetTag distributionSetTag) {
|
||||||
super(distributionSetTag);
|
super(distributionSetTag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||||
@@ -24,6 +25,7 @@ public class DistributionSetTagUpdatedEvent extends RemoteEntityEvent<Distributi
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public DistributionSetTagUpdatedEvent(final DistributionSetTag distributionSetTag) {
|
public DistributionSetTagUpdatedEvent(final DistributionSetTag distributionSetTag) {
|
||||||
super(distributionSetTag);
|
super(distributionSetTag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||||
@@ -25,6 +26,7 @@ public class DistributionSetTypeCreatedEvent extends RemoteEntityEvent<Distribut
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public DistributionSetTypeCreatedEvent(final DistributionSetType distributionSetType) {
|
public DistributionSetTypeCreatedEvent(final DistributionSetType distributionSetType) {
|
||||||
super(distributionSetType);
|
super(distributionSetType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||||
@@ -26,6 +27,7 @@ public class DistributionSetTypeUpdatedEvent extends RemoteEntityEvent<Distribut
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public DistributionSetTypeUpdatedEvent(final DistributionSetType distributionSetType) {
|
public DistributionSetTypeUpdatedEvent(final DistributionSetType distributionSetType) {
|
||||||
super(distributionSetType);
|
super(distributionSetType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@@ -28,6 +29,7 @@ public class DistributionSetUpdatedEvent extends RemoteEntityEvent<DistributionS
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public DistributionSetUpdatedEvent(final DistributionSet distributionSet) {
|
public DistributionSetUpdatedEvent(final DistributionSet distributionSet) {
|
||||||
super(distributionSet);
|
super(distributionSet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||||
@@ -24,6 +25,7 @@ public class RolloutCreatedEvent extends RemoteEntityEvent<Rollout> implements E
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public RolloutCreatedEvent(final Rollout rollout) {
|
public RolloutCreatedEvent(final Rollout rollout) {
|
||||||
super(rollout);
|
super(rollout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||||
@@ -25,6 +26,7 @@ public class RolloutGroupCreatedEvent extends AbstractRolloutGroupEvent implemen
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public RolloutGroupCreatedEvent(final RolloutGroup rolloutGroup, final Long rolloutId) {
|
public RolloutGroupCreatedEvent(final RolloutGroup rolloutGroup, final Long rolloutId) {
|
||||||
super(rolloutGroup, rolloutId);
|
super(rolloutGroup, rolloutId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||||
@@ -24,6 +25,7 @@ public class RolloutGroupUpdatedEvent extends AbstractRolloutGroupEvent implemen
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 2L;
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public RolloutGroupUpdatedEvent(final RolloutGroup rolloutGroup, final Long rolloutId) {
|
public RolloutGroupUpdatedEvent(final RolloutGroup rolloutGroup, final Long rolloutId) {
|
||||||
super(rolloutGroup, rolloutId);
|
super(rolloutGroup, rolloutId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||||
@@ -24,6 +25,7 @@ public class RolloutUpdatedEvent extends RemoteEntityEvent<Rollout> implements E
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public RolloutUpdatedEvent(final Rollout rollout) {
|
public RolloutUpdatedEvent(final Rollout rollout) {
|
||||||
super(rollout);
|
super(rollout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
@@ -24,6 +25,7 @@ public class SoftwareModuleCreatedEvent extends RemoteEntityEvent<SoftwareModule
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public SoftwareModuleCreatedEvent(final SoftwareModule softwareModule) {
|
public SoftwareModuleCreatedEvent(final SoftwareModule softwareModule) {
|
||||||
super(softwareModule);
|
super(softwareModule);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||||
@@ -24,6 +25,7 @@ public class SoftwareModuleTypeCreatedEvent extends RemoteEntityEvent<SoftwareMo
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public SoftwareModuleTypeCreatedEvent(final SoftwareModuleType softwareModuleType) {
|
public SoftwareModuleTypeCreatedEvent(final SoftwareModuleType softwareModuleType) {
|
||||||
super(softwareModuleType);
|
super(softwareModuleType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||||
@@ -25,6 +26,7 @@ public class SoftwareModuleTypeUpdatedEvent extends RemoteEntityEvent<SoftwareMo
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public SoftwareModuleTypeUpdatedEvent(final SoftwareModuleType softwareModuleType) {
|
public SoftwareModuleTypeUpdatedEvent(final SoftwareModuleType softwareModuleType) {
|
||||||
super(softwareModuleType);
|
super(softwareModuleType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
@@ -25,6 +26,7 @@ public class SoftwareModuleUpdatedEvent extends RemoteEntityEvent<SoftwareModule
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public SoftwareModuleUpdatedEvent(final SoftwareModule softwareModule) {
|
public SoftwareModuleUpdatedEvent(final SoftwareModule softwareModule) {
|
||||||
super(softwareModule);
|
super(softwareModule);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
@@ -24,6 +25,7 @@ public class TargetCreatedEvent extends RemoteEntityEvent<Target> implements Ent
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TargetCreatedEvent(final Target target) {
|
public TargetCreatedEvent(final Target target) {
|
||||||
super(target);
|
super(target);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||||
@@ -24,6 +25,7 @@ public class TargetFilterQueryCreatedEvent extends RemoteEntityEvent<TargetFilte
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TargetFilterQueryCreatedEvent(final TargetFilterQuery targetFilterQuery) {
|
public TargetFilterQueryCreatedEvent(final TargetFilterQuery targetFilterQuery) {
|
||||||
super(targetFilterQuery);
|
super(targetFilterQuery);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||||
@@ -24,6 +25,7 @@ public class TargetFilterQueryUpdatedEvent extends RemoteEntityEvent<TargetFilte
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TargetFilterQueryUpdatedEvent(final TargetFilterQuery targetFilterQuery) {
|
public TargetFilterQueryUpdatedEvent(final TargetFilterQuery targetFilterQuery) {
|
||||||
super(targetFilterQuery);
|
super(targetFilterQuery);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||||
@@ -24,6 +25,7 @@ public class TargetTagCreatedEvent extends RemoteEntityEvent<TargetTag> implemen
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TargetTagCreatedEvent(final TargetTag targetTag) {
|
public TargetTagCreatedEvent(final TargetTag targetTag) {
|
||||||
super(targetTag);
|
super(targetTag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||||
@@ -24,6 +25,7 @@ public class TargetTagUpdatedEvent extends RemoteEntityEvent<TargetTag> implemen
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TargetTagUpdatedEvent(final TargetTag targetTag) {
|
public TargetTagUpdatedEvent(final TargetTag targetTag) {
|
||||||
super(targetTag);
|
super(targetTag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
@@ -25,6 +26,7 @@ public class TargetTypeCreatedEvent extends RemoteEntityEvent<TargetType> implem
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TargetTypeCreatedEvent(final TargetType targetType) {
|
public TargetTypeCreatedEvent(final TargetType targetType) {
|
||||||
super(targetType);
|
super(targetType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
@@ -25,6 +26,7 @@ public class TargetTypeUpdatedEvent extends RemoteEntityEvent<TargetType> implem
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TargetTypeUpdatedEvent(final TargetType targetType) {
|
public TargetTypeUpdatedEvent(final TargetType targetType) {
|
||||||
super(targetType);
|
super(targetType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
@@ -24,6 +25,7 @@ public class TargetUpdatedEvent extends RemoteEntityEvent<Target> implements Ent
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TargetUpdatedEvent(final Target target) {
|
public TargetUpdatedEvent(final Target target) {
|
||||||
super(target);
|
super(target);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||||
@@ -24,6 +25,7 @@ public class TenantConfigurationCreatedEvent extends RemoteEntityEvent<TenantCon
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TenantConfigurationCreatedEvent(final TenantConfiguration tenantConfiguration) {
|
public TenantConfigurationCreatedEvent(final TenantConfiguration tenantConfiguration) {
|
||||||
super(tenantConfiguration);
|
super(tenantConfiguration);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.event.remote.entity;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||||
@@ -25,6 +26,7 @@ public class TenantConfigurationUpdatedEvent extends RemoteEntityEvent<TenantCon
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public TenantConfigurationUpdatedEvent(final TenantConfiguration tenantConfiguration) {
|
public TenantConfigurationUpdatedEvent(final TenantConfiguration tenantConfiguration) {
|
||||||
super(tenantConfiguration);
|
super(tenantConfiguration);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,10 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-context-support</artifactId>
|
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.protostuff</groupId>
|
<groupId>io.protostuff</groupId>
|
||||||
<artifactId>protostuff-core</artifactId>
|
<artifactId>protostuff-core</artifactId>
|
||||||
@@ -42,9 +43,5 @@
|
|||||||
<artifactId>protostuff-runtime</artifactId>
|
<artifactId>protostuff-runtime</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made
|
||||||
|
* available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.event;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.HawkbitAutoConfiguration;
|
||||||
|
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link EventJacksonConfiguration} adds to the {@link tools.jackson.databind.json.JsonMapper} configuration
|
||||||
|
* (already modified by the {@link HawkbitAutoConfiguration}) the event subtypes defined in {@link EventType}
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Import(HawkbitAutoConfiguration.class)
|
||||||
|
public class EventJacksonConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
JsonMapperBuilderCustomizer jsonMapperBuilderCustomizer() {
|
||||||
|
return jsonMapperBuilder -> jsonMapperBuilder.registerSubtypes(EventType.getNamedTypes());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,30 +9,35 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.event;
|
package org.eclipse.hawkbit.event;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
import org.springframework.messaging.converter.JacksonJsonMessageConverter;
|
||||||
import org.springframework.util.MimeType;
|
import org.springframework.util.MimeType;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
public class EventJacksonMessageConverter extends MappingJackson2MessageConverter {
|
public class EventJacksonMessageConverter extends JacksonJsonMessageConverter {
|
||||||
|
|
||||||
public static final MimeType APPLICATION_REMOTE_EVENT_JSON = new MimeType("application", "remote-event-json");
|
public static final MimeType APPLICATION_REMOTE_EVENT_JSON = new MimeType("application", "remote-event-json");
|
||||||
|
|
||||||
public EventJacksonMessageConverter() {
|
public EventJacksonMessageConverter(final JsonMapper mapper) {
|
||||||
super(APPLICATION_REMOTE_EVENT_JSON);
|
super(mapper, APPLICATION_REMOTE_EVENT_JSON);
|
||||||
final ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
EventType.getNamedTypes().forEach(objectMapper::registerSubtypes);
|
|
||||||
setObjectMapper(objectMapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object convertToInternal(final Object payload, final MessageHeaders headers, final Object conversionHint) {
|
@SuppressWarnings("java:S1185") // intentionally override in order to extend visibility
|
||||||
|
@NullMarked
|
||||||
|
@Nullable
|
||||||
|
protected Object convertToInternal(final Object payload, @Nullable final MessageHeaders headers, @Nullable final Object conversionHint) {
|
||||||
return super.convertToInternal(payload, headers, conversionHint);
|
return super.convertToInternal(payload, headers, conversionHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object convertFromInternal(final Message<?> message, final Class<?> targetClass, final Object conversionHint) {
|
@SuppressWarnings("java:S1185") // intentionally override in order to extend visibility
|
||||||
|
@NullMarked
|
||||||
|
@Nullable
|
||||||
|
protected Object convertFromInternal(final Message<?> message, final Class<?> targetClass, @Nullable final Object conversionHint) {
|
||||||
return super.convertFromInternal(message, targetClass, conversionHint);
|
return super.convertFromInternal(message, targetClass, conversionHint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,8 @@ import io.protostuff.Schema;
|
|||||||
import io.protostuff.runtime.RuntimeSchema;
|
import io.protostuff.runtime.RuntimeSchema;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
|
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
import org.springframework.messaging.converter.AbstractMessageConverter;
|
import org.springframework.messaging.converter.AbstractMessageConverter;
|
||||||
@@ -46,18 +48,20 @@ public class EventProtoStuffMessageConverter extends AbstractMessageConverter {
|
|||||||
public static final MimeType APPLICATION_BINARY_PROTOSTUFF = new MimeType("application", "binary+protostuff");
|
public static final MimeType APPLICATION_BINARY_PROTOSTUFF = new MimeType("application", "binary+protostuff");
|
||||||
private static final int HEADER_LENGTH_PREFIX_SIZE = 4;
|
private static final int HEADER_LENGTH_PREFIX_SIZE = 4;
|
||||||
|
|
||||||
|
|
||||||
public EventProtoStuffMessageConverter() {
|
public EventProtoStuffMessageConverter() {
|
||||||
super(APPLICATION_BINARY_PROTOSTUFF);
|
super(APPLICATION_BINARY_PROTOSTUFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NullMarked
|
||||||
protected boolean supports(final Class<?> aClass) {
|
protected boolean supports(final Class<?> aClass) {
|
||||||
return AbstractRemoteEvent.class.isAssignableFrom(aClass);
|
return AbstractRemoteEvent.class.isAssignableFrom(aClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object convertFromInternal(final Message<?> message, final Class<?> targetClass, final Object conversionHint) {
|
@NullMarked
|
||||||
|
@Nullable
|
||||||
|
protected Object convertFromInternal(final Message<?> message, final Class<?> targetClass, @Nullable final Object conversionHint) {
|
||||||
final Object objectPayload = message.getPayload();
|
final Object objectPayload = message.getPayload();
|
||||||
if (objectPayload instanceof byte[] payload) {
|
if (objectPayload instanceof byte[] payload) {
|
||||||
final byte[] clazzHeader = extractClazzHeader(payload);
|
final byte[] clazzHeader = extractClazzHeader(payload);
|
||||||
@@ -112,7 +116,6 @@ public class EventProtoStuffMessageConverter extends AbstractMessageConverter {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static EventType readClassHeader(final byte[] typeInformation) {
|
private static EventType readClassHeader(final byte[] typeInformation) {
|
||||||
final Schema<EventType> schema = RuntimeSchema.getSchema(EventType.class);
|
final Schema<EventType> schema = RuntimeSchema.getSchema(EventType.class);
|
||||||
final EventType deserializedType = schema.newMessage();
|
final EventType deserializedType = schema.newMessage();
|
||||||
@@ -134,8 +137,7 @@ public class EventProtoStuffMessageConverter extends AbstractMessageConverter {
|
|||||||
throw new MessageConversionException("Missing EventType for given class : " + clazz);
|
throw new MessageConversionException("Missing EventType for given class : " + clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked") final Schema<Object> schema = (Schema<Object>) RuntimeSchema.getSchema((Class<?>) EventType.class);
|
||||||
final Schema<Object> schema = (Schema<Object>) RuntimeSchema.getSchema((Class<?>) EventType.class);
|
|
||||||
final LinkedBuffer buffer = LinkedBuffer.allocate();
|
final LinkedBuffer buffer = LinkedBuffer.allocate();
|
||||||
byte[] typeBytes = ProtobufIOUtil.toByteArray(clazzEventType, schema, buffer);
|
byte[] typeBytes = ProtobufIOUtil.toByteArray(clazzEventType, schema, buffer);
|
||||||
|
|
||||||
|
|||||||
@@ -29,17 +29,20 @@ import org.springframework.context.ApplicationEvent;
|
|||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.event.ApplicationEventMulticaster;
|
import org.springframework.context.event.ApplicationEventMulticaster;
|
||||||
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||||
import org.springframework.context.support.AbstractApplicationContext;
|
import org.springframework.context.support.AbstractApplicationContext;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.messaging.converter.MessageConverter;
|
import org.springframework.messaging.converter.MessageConverter;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Autoconfiguration for the events.
|
* Autoconfiguration for the events publishing.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@Import(EventJacksonConfiguration.class)
|
||||||
public class EventPublisherConfiguration {
|
public class EventPublisherConfiguration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,15 +111,21 @@ public class EventPublisherConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Consumer<AbstractRemoteEvent> serviceEventConsumer(ApplicationEventPublisher publisher) {
|
public Consumer<AbstractRemoteEvent> serviceEventConsumer(final ApplicationEventPublisher publisher) {
|
||||||
return publisher::publishEvent;
|
return publisher::publishEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Consumer<AbstractRemoteEvent> fanoutEventConsumer(ApplicationEventPublisher publisher) {
|
public Consumer<AbstractRemoteEvent> fanoutEventConsumer(final ApplicationEventPublisher publisher) {
|
||||||
return publisher::publishEvent;
|
return publisher::publishEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MessageConverter eventJacksonMessageConverter(final JsonMapper mapper) {
|
||||||
|
return new EventJacksonMessageConverter(mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
@ConditionalOnClass({ Schema.class, ProtostuffIOUtil.class })
|
@ConditionalOnClass({ Schema.class, ProtostuffIOUtil.class })
|
||||||
protected static class EventProtostuffConfiguration {
|
protected static class EventProtostuffConfiguration {
|
||||||
|
|
||||||
@@ -125,9 +134,4 @@ public class EventPublisherConfiguration {
|
|||||||
return new EventProtoStuffMessageConverter();
|
return new EventProtoStuffMessageConverter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public MessageConverter eventJacksonMessageConverter() {
|
|
||||||
return new EventJacksonMessageConverter();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.event;
|
package org.eclipse.hawkbit.event;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@@ -72,15 +70,14 @@ import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceE
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetPollServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetPollServiceEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent;
|
import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent;
|
||||||
|
import tools.jackson.databind.jsontype.NamedType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link EventType} class declares the event-type and it's corresponding
|
* The {@link EventType} class declares the event-type, and it's corresponding encoding value in the payload of a remote header.
|
||||||
* encoding value in the payload of an remote header. The event-type is encoded
|
* The event-type is encoded into the payload of the message which is distributed.
|
||||||
* into the payload of the message which is distributed.
|
* <p/>
|
||||||
*
|
* To encode and decode the event class type we need some conversation mapping between the actual class and the corresponding integer value
|
||||||
* To encode and decode the event class type we need some conversation mapping
|
* which is the encoded value in the byte-payload.
|
||||||
* between the actual class and the corresponding integer value which is the
|
|
||||||
* encoded value in the byte-payload.
|
|
||||||
*/
|
*/
|
||||||
// for marshalling and unmarshalling.
|
// for marshalling and unmarshalling.
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@@ -93,8 +90,7 @@ public class EventType {
|
|||||||
|
|
||||||
private int value;
|
private int value;
|
||||||
|
|
||||||
// The associated event-type-value must remain the same as initially
|
// The associated event-type-value must remain the same as initially declared. Otherwise, messages cannot correctly de-serialized.
|
||||||
// declared. Otherwise, messages cannot correctly de-serialized.
|
|
||||||
static {
|
static {
|
||||||
// target
|
// target
|
||||||
TYPES.put(1, TargetCreatedEvent.class);
|
TYPES.put(1, TargetCreatedEvent.class);
|
||||||
@@ -215,9 +211,9 @@ public class EventType {
|
|||||||
return TYPES.get(value);
|
return TYPES.get(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<NamedType> getNamedTypes() {
|
public static NamedType[] getNamedTypes() {
|
||||||
return TYPES.entrySet().stream()
|
return TYPES.entrySet().stream()
|
||||||
.map(e -> new NamedType(e.getValue(), String.valueOf(e.getKey())))
|
.map(e -> new NamedType(e.getValue(), String.valueOf(e.getKey())))
|
||||||
.toList();
|
.toArray(NamedType[]::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,20 +35,14 @@ import org.springframework.messaging.converter.MessageConverter;
|
|||||||
|
|
||||||
abstract class AbstractEventMessageConverterTest {
|
abstract class AbstractEventMessageConverterTest {
|
||||||
|
|
||||||
protected final MessageConverter messageConverter;
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
protected Message<Object> messageMock;
|
protected Message<Object> messageMock;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
protected Target targetMock;
|
protected Target targetMock;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
protected Action actionMock;
|
protected Action actionMock;
|
||||||
|
|
||||||
AbstractEventMessageConverterTest(MessageConverter messageConverter) {
|
protected abstract MessageConverter messageConverter();
|
||||||
this.messageConverter = messageConverter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that the TargetCreatedEvent can be successfully serialized and deserialized
|
* Verifies that the TargetCreatedEvent can be successfully serialized and deserialized
|
||||||
@@ -82,11 +76,8 @@ abstract class AbstractEventMessageConverterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void successfullySerializeAndDeserializeActionServiceEvent() {
|
void successfullySerializeAndDeserializeActionServiceEvent() {
|
||||||
final ActionCreatedServiceEvent actionCreatedServiceEvent =
|
final ActionCreatedServiceEvent actionCreatedServiceEvent = new ActionCreatedServiceEvent(createActionCreatedEvent());
|
||||||
new ActionCreatedServiceEvent(createActionCreatedEvent());
|
final ActionUpdatedServiceEvent actionUpdatedServiceEvent = new ActionUpdatedServiceEvent(createActionUpdatedEvent());
|
||||||
|
|
||||||
final ActionUpdatedServiceEvent actionUpdatedServiceEvent =
|
|
||||||
new ActionUpdatedServiceEvent(createActionUpdatedEvent());
|
|
||||||
|
|
||||||
assertSerializeAndDeserialize(actionCreatedServiceEvent, ActionCreatedServiceEvent.class);
|
assertSerializeAndDeserialize(actionCreatedServiceEvent, ActionCreatedServiceEvent.class);
|
||||||
assertSerializeAndDeserialize(actionUpdatedServiceEvent, ActionUpdatedServiceEvent.class);
|
assertSerializeAndDeserialize(actionUpdatedServiceEvent, ActionUpdatedServiceEvent.class);
|
||||||
@@ -112,7 +103,9 @@ abstract class AbstractEventMessageConverterTest {
|
|||||||
return new ActionUpdatedEvent(actionMock, 1L, 2L, 3L);
|
return new ActionUpdatedEvent(actionMock, 1L, 2L, 3L);
|
||||||
}
|
}
|
||||||
|
|
||||||
<T extends AbstractRemoteEvent> void assertSerializeAndDeserialize(T event, Class<? extends AbstractRemoteEvent> expectedClass) {
|
private <T extends AbstractRemoteEvent> void assertSerializeAndDeserialize(
|
||||||
|
final T event, final Class<? extends AbstractRemoteEvent> expectedClass) {
|
||||||
|
final MessageConverter messageConverter = messageConverter();
|
||||||
// serialize
|
// serialize
|
||||||
Object serializedEvent = null;
|
Object serializedEvent = null;
|
||||||
if (messageConverter instanceof EventProtoStuffMessageConverter protoStuff) {
|
if (messageConverter instanceof EventProtoStuffMessageConverter protoStuff) {
|
||||||
@@ -135,4 +128,4 @@ abstract class AbstractEventMessageConverterTest {
|
|||||||
.isInstanceOf(expectedClass)
|
.isInstanceOf(expectedClass)
|
||||||
.isEqualTo(event);
|
.isEqualTo(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,13 +9,27 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.event;
|
package org.eclipse.hawkbit.event;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.messaging.converter.MessageConverter;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
@SpringBootTest(classes = EventJacksonConfiguration.class)
|
||||||
class EventJacksonMessageConverterTest extends AbstractEventMessageConverterTest {
|
class EventJacksonMessageConverterTest extends AbstractEventMessageConverterTest {
|
||||||
|
|
||||||
EventJacksonMessageConverterTest() {
|
private MessageConverter messageConverter;
|
||||||
super(new EventJacksonMessageConverter());
|
|
||||||
|
@Autowired
|
||||||
|
void setJsonMapper(final JsonMapper jsonMapper) {
|
||||||
|
messageConverter = new EventJacksonMessageConverter(jsonMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MessageConverter messageConverter() {
|
||||||
|
return Objects.requireNonNull(messageConverter, "MessageConverter has not been initialized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,12 +21,15 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
import org.springframework.messaging.converter.MessageConversionException;
|
import org.springframework.messaging.converter.MessageConversionException;
|
||||||
|
import org.springframework.messaging.converter.MessageConverter;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class EventProtoStuffMessageConverterTest extends AbstractEventMessageConverterTest {
|
class EventProtoStuffMessageConverterTest extends AbstractEventMessageConverterTest {
|
||||||
|
|
||||||
EventProtoStuffMessageConverterTest() {
|
private static final EventProtoStuffMessageConverter MESSAGE_CONVERTER = new EventProtoStuffMessageConverter();
|
||||||
super(new EventProtoStuffMessageConverter());
|
|
||||||
|
protected MessageConverter messageConverter() {
|
||||||
|
return MESSAGE_CONVERTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +42,7 @@ class EventProtoStuffMessageConverterTest extends AbstractEventMessageConverterT
|
|||||||
|
|
||||||
assertThatExceptionOfType(MessageConversionException.class)
|
assertThatExceptionOfType(MessageConversionException.class)
|
||||||
.as("Missing MessageConversationException for un-defined event-type")
|
.as("Missing MessageConversationException for un-defined event-type")
|
||||||
.isThrownBy(() -> ((EventProtoStuffMessageConverter)messageConverter).convertToInternal(dummyEvent, messageHeaders, null));
|
.isThrownBy(() -> MESSAGE_CONVERTER.convertToInternal(dummyEvent, messageHeaders, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -41,12 +41,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.hibernate.orm</groupId>
|
|
||||||
<artifactId>hibernate-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -33,24 +33,23 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.persistence</groupId>
|
||||||
|
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
||||||
|
<version>${eclipselink.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.micrometer</groupId>
|
<groupId>io.micrometer</groupId>
|
||||||
<artifactId>micrometer-core</artifactId>
|
<artifactId>micrometer-core</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Static class generation -->
|
<dependency> <!-- Static class generation -->
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate.orm</groupId>
|
<groupId>org.hibernate.orm</groupId>
|
||||||
<artifactId>hibernate-jpamodelgen</artifactId>
|
<artifactId>hibernate-processor</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.persistence</groupId>
|
|
||||||
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
|
||||||
<version>${eclipselink.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -71,13 +70,6 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<basePackage>org.eclipse.hawkbit.repository.jpa.model</basePackage>
|
<basePackage>org.eclipse.hawkbit.repository.jpa.model</basePackage>
|
||||||
</configuration>
|
</configuration>
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.persistence</groupId>
|
|
||||||
<artifactId>org.eclipse.persistence.jpa</artifactId>
|
|
||||||
<version>${eclipselink.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import jakarta.persistence.PersistenceException;
|
|||||||
import org.eclipse.hawkbit.repository.jpa.utils.JpaExceptionTranslator;
|
import org.eclipse.hawkbit.repository.jpa.utils.JpaExceptionTranslator;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
|
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
|
||||||
import org.springframework.lang.NonNull;
|
import org.jspecify.annotations.NonNull;
|
||||||
import org.springframework.orm.jpa.JpaSystemException;
|
import org.springframework.orm.jpa.JpaSystemException;
|
||||||
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
|
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ import javax.sql.DataSource;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
|
||||||
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.jpa.autoconfigure.JpaBaseConfiguration;
|
||||||
|
import org.springframework.boot.jpa.autoconfigure.JpaProperties;
|
||||||
|
import org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizers;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
@@ -38,7 +38,7 @@ import org.springframework.transaction.jta.JtaTransactionManager;
|
|||||||
public class JpaConfiguration extends JpaBaseConfiguration {
|
public class JpaConfiguration extends JpaBaseConfiguration {
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ConfigurationProperties // predix is "/" intentionally
|
@ConfigurationProperties // prefix is "/" intentionally
|
||||||
protected static class Properties {
|
protected static class Properties {
|
||||||
|
|
||||||
private final Map<String, String> eclipselink = new HashMap<>();
|
private final Map<String, String> eclipselink = new HashMap<>();
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|||||||
* <ol>
|
* <ol>
|
||||||
* <li>The Spring property spring.jpa.properties.eclipselink.profiler=PerformanceMonitor shall be set - enables Eclipselink statistics
|
* <li>The Spring property spring.jpa.properties.eclipselink.profiler=PerformanceMonitor shall be set - enables Eclipselink statistics
|
||||||
* collecting</li>
|
* collecting</li>
|
||||||
* <li>By default the periodic stdout log is disabled by setting hawkbit.jpa.statistics.dump-period-ms=9223372036854775807 (Long.MAX_VALUE) -
|
* <li>By default, the periodic stdout log is disabled by setting hawkbit.jpa.statistics.dump-period-ms=9223372036854775807 (Long.MAX_VALUE) -
|
||||||
* i.e. effectively <b>never</b>. If log is required it should be set to the required period</li>
|
* i.e. effectively <b>never</b>. If log is required it should be set to the required period</li>
|
||||||
* <li>The MeterRegistry shall be registered available - e.g. include org.springframework.boot:spring-boot-actuator-autoconfigure</li>
|
* <li>The MeterRegistry shall be registered and available</li>
|
||||||
* <li>(?) When using in test the metrics MAYBE shall be enabled with @AutoConfigureObservability(tracing = false)</li>
|
* <li>(?) When using in test the metrics MAYBE shall be enabled with @AutoConfigureObservability(tracing = false)</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -24,16 +24,7 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot</artifactId>
|
<artifactId>spring-boot-starter-flyway</artifactId>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-core</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
package org.eclipse.hawkbit.autoconfigure.repository.jpa.flyway;
|
package org.eclipse.hawkbit.autoconfigure.repository.jpa.flyway;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
import org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE SP_LOCK ADD COLUMN EXPIRED_AFTER TIMESTAMP NOT NULL;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE SP_LOCK ADD COLUMN EXPIRED_AFTER DATETIME(6) NOT NULL;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE SP_LOCK ADD COLUMN EXPIRED_AFTER TIMESTAMP NOT NULL;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user