From 5f2117b5b52ee26baf004f046b5af643ba8b6674 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Fri, 14 Jun 2024 06:04:51 +0200 Subject: [PATCH] fix potential class loading deadlock in HsHostingAssetEntityValidator --- .../asset/HsHostingAssetController.java | 9 ++-- .../asset/HsHostingAssetPropsController.java | 7 +-- .../HsHostingAssetEntityValidator.java | 45 ++--------------- ...HsHostingAssetEntityValidatorRegistry.java | 50 +++++++++++++++++++ ...udServerHostingAssetValidatorUnitTest.java | 5 +- ...HsHostingAssetEntityValidatorUnitTest.java | 3 +- ...edServerHostingAssetValidatorUnitTest.java | 3 +- ...WebspaceHostingAssetValidatorUnitTest.java | 6 +-- 8 files changed, 69 insertions(+), 59 deletions(-) create mode 100644 src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorRegistry.java diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetController.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetController.java index 60c0ebef..13bb43dd 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetController.java @@ -1,5 +1,6 @@ package net.hostsharing.hsadminng.hs.hosting.asset; +import net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidatorRegistry; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetsApi; import net.hostsharing.hsadminng.context.Context; @@ -20,8 +21,6 @@ import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; -import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidator.validated; - @RestController public class HsHostingAssetController implements HsHostingAssetsApi { @@ -62,7 +61,8 @@ public class HsHostingAssetController implements HsHostingAssetsApi { final var entityToSave = mapper.map(body, HsHostingAssetEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER); - final var saved = validated(assetRepo.save(entityToSave)); + final HsHostingAssetEntity persistentEntity = assetRepo.save(entityToSave); + final var saved = HsHostingAssetEntityValidatorRegistry.validated(persistentEntity); final var uri = MvcUriComponentsBuilder.fromController(getClass()) @@ -117,7 +117,8 @@ public class HsHostingAssetController implements HsHostingAssetsApi { new HsHostingAssetEntityPatcher(current).apply(body); - final var saved = validated(assetRepo.save(current)); + final HsHostingAssetEntity persistentEntity = assetRepo.save(current); + final var saved = HsHostingAssetEntityValidatorRegistry.validated(persistentEntity); final var mapped = mapper.map(saved, HsHostingAssetResource.class); return ResponseEntity.ok(mapped); } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsController.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsController.java index 97a50cb1..0da530bd 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsController.java @@ -1,6 +1,6 @@ package net.hostsharing.hsadminng.hs.hosting.asset; -import net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidator; +import net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidatorRegistry; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetPropsApi; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetTypeResource; import org.springframework.http.ResponseEntity; @@ -15,7 +15,7 @@ public class HsHostingAssetPropsController implements HsHostingAssetPropsApi { @Override public ResponseEntity> listAssetTypes() { - final var resource = HsHostingAssetEntityValidator.types().stream() + final var resource = HsHostingAssetEntityValidatorRegistry.types().stream() .map(Enum::name) .toList(); return ResponseEntity.ok(resource); @@ -25,7 +25,8 @@ public class HsHostingAssetPropsController implements HsHostingAssetPropsApi { public ResponseEntity> listAssetTypeProps( final HsHostingAssetTypeResource assetType) { - final var propValidators = HsHostingAssetEntityValidator.forType(HsHostingAssetType.of(assetType)); + final Enum type = HsHostingAssetType.of(assetType); + final var propValidators = HsHostingAssetEntityValidatorRegistry.forType(type); final List> resource = propValidators.properties(); return ResponseEntity.ok(toListOfObjects(resource)); } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidator.java index 9354be6e..44d5fbfe 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidator.java @@ -3,59 +3,18 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity; import net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityValidatorRegistry; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; -import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType; import net.hostsharing.hsadminng.hs.validation.HsEntityValidator; -import net.hostsharing.hsadminng.hs.validation.MultiValidationException; import net.hostsharing.hsadminng.hs.validation.ValidatableProperty; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.Set; import static java.util.Arrays.stream; import static java.util.Collections.emptyList; import static java.util.Optional.ofNullable; -import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.*; public class HsHostingAssetEntityValidator extends HsEntityValidator { - private static final Map, HsEntityValidator> validators = new HashMap<>(); - static { - register(CLOUD_SERVER, new HsHostingAssetEntityValidator()); - register(MANAGED_SERVER, new HsManagedServerHostingAssetValidator()); - register(MANAGED_WEBSPACE, new HsManagedWebspaceHostingAssetValidator()); - register(UNIX_USER, new HsHostingAssetEntityValidator()); - } - - private static void register(final Enum type, final HsEntityValidator validator) { - stream(validator.propertyValidators).forEach( entry -> { - entry.verifyConsistency(Map.entry(type, validator)); - }); - validators.put(type, validator); - } - - public static HsEntityValidator forType(final Enum type) { - if ( validators.containsKey(type)) { - return validators.get(type); - } - throw new IllegalArgumentException("no validator found for type " + type); - } - - public static Set> types() { - return validators.keySet(); - } - - public static List doValidate(final HsHostingAssetEntity hostingAsset) { - return HsHostingAssetEntityValidator.forType(hostingAsset.getType()).validate(hostingAsset); - } - - public static HsHostingAssetEntity validated(final HsHostingAssetEntity entityToSave) { - MultiValidationException.throwInvalid(doValidate(entityToSave)); - return entityToSave; - } - public HsHostingAssetEntityValidator(final ValidatableProperty... properties) { super(properties); } @@ -72,7 +31,9 @@ public class HsHostingAssetEntityValidator extends HsEntityValidator optionallyValidate(final HsHostingAssetEntity assetEntity) { - return assetEntity != null ? forType(assetEntity.getType()).validate(assetEntity) : emptyList(); + return assetEntity != null ? + HsHostingAssetEntityValidatorRegistry.forType(assetEntity.getType()).validate(assetEntity) : + emptyList(); } private static List optionallyValidate(final HsBookingItemEntity bookingItem) { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorRegistry.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorRegistry.java new file mode 100644 index 00000000..2465fdfe --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorRegistry.java @@ -0,0 +1,50 @@ +package net.hostsharing.hsadminng.hs.hosting.asset.validators; + +import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; +import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType; +import net.hostsharing.hsadminng.hs.validation.HsEntityValidator; +import net.hostsharing.hsadminng.hs.validation.MultiValidationException; + +import java.util.*; + +import static java.util.Arrays.stream; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.*; + +public class HsHostingAssetEntityValidatorRegistry { + + private static final Map, HsEntityValidator> validators = new HashMap<>(); + static { + register(CLOUD_SERVER, new HsHostingAssetEntityValidator()); + register(MANAGED_SERVER, new HsManagedServerHostingAssetValidator()); + register(MANAGED_WEBSPACE, new HsManagedWebspaceHostingAssetValidator()); + register(UNIX_USER, new HsHostingAssetEntityValidator()); + } + + private static void register(final Enum type, final HsEntityValidator validator) { + stream(validator.propertyValidators).forEach( entry -> { + entry.verifyConsistency(Map.entry(type, validator)); + }); + validators.put(type, validator); + } + + public static HsEntityValidator forType(final Enum type) { + if ( validators.containsKey(type)) { + return validators.get(type); + } + throw new IllegalArgumentException("no validator found for type " + type); + } + + public static Set> types() { + return validators.keySet(); + } + + public static List doValidate(final HsHostingAssetEntity hostingAsset) { + return HsHostingAssetEntityValidatorRegistry.forType(hostingAsset.getType()).validate(hostingAsset); + } + + public static HsHostingAssetEntity validated(final HsHostingAssetEntity entityToSave) { + MultiValidationException.throwInvalid(doValidate(entityToSave)); + return entityToSave; + } + +} diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsCloudServerHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsCloudServerHostingAssetValidatorUnitTest.java index 0e6e37b4..db17d9cc 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsCloudServerHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsCloudServerHostingAssetValidatorUnitTest.java @@ -7,7 +7,6 @@ import java.util.Map; import static java.util.Map.entry; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER; -import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidator.forType; import static org.assertj.core.api.Assertions.assertThat; class HsCloudServerHostingAssetValidatorUnitTest { @@ -22,7 +21,7 @@ class HsCloudServerHostingAssetValidatorUnitTest { entry("RAM", 2000) )) .build(); - final var validator = forType(cloudServerHostingAssetEntity.getType()); + final var validator = HsHostingAssetEntityValidatorRegistry.forType(cloudServerHostingAssetEntity.getType()); // when @@ -35,7 +34,7 @@ class HsCloudServerHostingAssetValidatorUnitTest { @Test void containsAllValidations() { // when - final var validator = forType(CLOUD_SERVER); + final var validator = HsHostingAssetEntityValidatorRegistry.forType(CLOUD_SERVER); // then assertThat(validator.properties()).map(Map::toString).isEmpty(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorUnitTest.java index 28fb5c6e..82371eaa 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorUnitTest.java @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test; import jakarta.validation.ValidationException; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER; -import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidator.validated; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; @@ -21,7 +20,7 @@ class HsHostingAssetEntityValidatorUnitTest { .build(); // when - final var result = catchThrowable( ()-> validated(managedServerHostingAssetEntity) ); + final var result = catchThrowable( ()-> HsHostingAssetEntityValidatorRegistry.validated(managedServerHostingAssetEntity)); // then assertThat(result).isInstanceOf(ValidationException.class) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsManagedServerHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsManagedServerHostingAssetValidatorUnitTest.java index 423da194..4a5eb400 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsManagedServerHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsManagedServerHostingAssetValidatorUnitTest.java @@ -7,7 +7,6 @@ import java.util.Map; import static java.util.Map.entry; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER; -import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidator.forType; import static org.assertj.core.api.Assertions.assertThat; class HsManagedServerHostingAssetValidatorUnitTest { @@ -24,7 +23,7 @@ class HsManagedServerHostingAssetValidatorUnitTest { entry("monit_max_ram_usage", 101) )) .build(); - final var validator = forType(mangedWebspaceHostingAssetEntity.getType()); + final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedWebspaceHostingAssetEntity.getType()); // when final var result = validator.validate(mangedWebspaceHostingAssetEntity); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsManagedWebspaceHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsManagedWebspaceHostingAssetValidatorUnitTest.java index 5bb39f92..6e530bb3 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsManagedWebspaceHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsManagedWebspaceHostingAssetValidatorUnitTest.java @@ -42,7 +42,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest { @Test void validatesIdentifier() { // given - final var validator = HsHostingAssetEntityValidator.forType(MANAGED_WEBSPACE); + final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE); final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() .type(MANAGED_WEBSPACE) .parentAsset(mangedServerAssetEntity) @@ -59,7 +59,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest { @Test void validatesUnknownProperties() { // given - final var validator = HsHostingAssetEntityValidator.forType(MANAGED_WEBSPACE); + final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE); final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() .type(MANAGED_WEBSPACE) .parentAsset(mangedServerAssetEntity) @@ -79,7 +79,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest { @Test void validatesValidEntity() { // given - final var validator = HsHostingAssetEntityValidator.forType(MANAGED_WEBSPACE); + final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE); final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() .type(MANAGED_WEBSPACE) .parentAsset(mangedServerAssetEntity)