From 4d1d4cb9e94dc3a27d2bfd87114d8e2dce8dc3a4 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Tue, 1 Oct 2024 09:51:16 +0200 Subject: [PATCH] refactor HsBookingItemCreatedListener - extracting factories --- .../asset/HsBookingItemCreatedListener.java | 196 ------------------ .../DomainSetupHostingAssetFactory.java | 128 ++++++++++++ .../asset/factories/HostingAssetFactory.java | 45 ++++ .../HsBookingItemCreatedListener.java | 40 ++++ 4 files changed, 213 insertions(+), 196 deletions(-) delete mode 100644 src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsBookingItemCreatedListener.java create mode 100644 src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/DomainSetupHostingAssetFactory.java create mode 100644 src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HostingAssetFactory.java create mode 100644 src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HsBookingItemCreatedListener.java diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsBookingItemCreatedListener.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsBookingItemCreatedListener.java deleted file mode 100644 index 72720601..00000000 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsBookingItemCreatedListener.java +++ /dev/null @@ -1,196 +0,0 @@ -package net.hostsharing.hsadminng.hs.hosting.asset; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetAutoInsertResource; -import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetSubInsertResource; -import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetTypeResource; -import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedAppEvent; -import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity; -import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity.HsHostingAssetRealEntityBuilder; -import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor; -import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; -import net.hostsharing.hsadminng.mapper.StandardMapper; -import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationListener; -import org.springframework.stereotype.Component; - -import jakarta.validation.ValidationException; -import java.net.IDN; -import java.util.List; -import java.util.UUID; -import java.util.function.Function; - -import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_HTTP_SETUP; -import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_MBOX_SETUP; -import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP; - -@Component -public class HsBookingItemCreatedListener implements ApplicationListener { - - @Autowired - private EntityManagerWrapper emw; - - @Autowired - private ObjectMapper jsonMapper; - - @Autowired - private StandardMapper standardMapper; - - @Override - @SneakyThrows - public void onApplicationEvent(final BookingItemCreatedAppEvent event) { - final var newBookingItemRealEntity = event.getEntity().getBookingItem(); - final var asset = jsonMapper.readValue(event.getEntity().getAssetJson(), HsHostingAssetAutoInsertResource.class); - final var factory = switch (newBookingItemRealEntity.getType()) { - case PRIVATE_CLOUD, CLOUD_SERVER, MANAGED_SERVER -> null; // for now, no automatic HostingAsset possible - case MANAGED_WEBSPACE -> null; // TODO.impl: implement ManagedWebspace HostingAsset creation, where possible - case DOMAIN_SETUP -> new DomainSetupHostingAssetFactory(newBookingItemRealEntity, asset); - }; - if (factory != null) { - event.getEntity().setStatusMessage(factory.performSaveProcess()); - emw.persist(event.getEntity()); // TODO.impl: once we implement retry, we might need merge - } - } - - private T ref(final Class entityClass, final UUID uuid) { - return uuid != null ? emw.getReference(entityClass, uuid) : null; - } - - @RequiredArgsConstructor - abstract class HostingAssetFactory { - - final HsBookingItemRealEntity fromBookingItem; - final HsHostingAssetAutoInsertResource asset; - - protected HsHostingAsset create() { - return null; - } - - String performSaveProcess() { - final var newHostingAsset = create(); - try { - persist(newHostingAsset); - return null; - } catch (final Exception e) { - return e.getMessage(); - } - } - - protected void persist(final HsHostingAsset newHostingAsset) { - new HostingAssetEntitySaveProcessor(emw, newHostingAsset) - .preprocessEntity() - .validateEntity() - .prepareForSave() - .save() - .validateContext(); - } - } - - class DomainSetupHostingAssetFactory extends HostingAssetFactory { - - public DomainSetupHostingAssetFactory( - final HsBookingItemRealEntity newBookingItemRealEntity, - final HsHostingAssetAutoInsertResource asset) { - super(newBookingItemRealEntity, asset); - } - - @Override - protected HsHostingAsset create() { - final var domainSetupAsset = createDomainSetupAsset(getDomainName()); - - // TODO.legacy: as long as we need to be compatible, we always do all technical domain-setups - final var subHostingAssetResources = getSubHostingAssetResources(); - final var domainHttpSetupAsset = createDomainHttpSetupAssetEntity( - subHostingAssetResources, - getDomainName(), - domainSetupAsset); - final var assignedToUnixUserAsset = domainHttpSetupAsset.getAssignedToAsset(); - - // TODO.legacy: don't create DNS setup as long as we need to remain support legacy web-ui etc. - - createDomainSubSetupAssetEntity( - domainSetupAsset, - DOMAIN_MBOX_SETUP, - builder -> builder - .assignedToAsset(assignedToUnixUserAsset.getParentAsset()) - .identifier(getDomainName() + "|MBOX") - .caption("HTTP-Setup für " + IDN.toUnicode(getDomainName()))); - - createDomainSubSetupAssetEntity( - domainSetupAsset, - DOMAIN_SMTP_SETUP, - builder -> builder - .assignedToAsset(assignedToUnixUserAsset.getParentAsset()) - .identifier(getDomainName() + "|SMTP") - .caption("HTTP-Setup für " + IDN.toUnicode(getDomainName()))); - - return domainSetupAsset; - } - - private HsHostingAssetRealEntity createDomainSetupAsset(final String domainName) { - return HsHostingAssetRealEntity.builder() - .bookingItem(fromBookingItem) - .type(HsHostingAssetType.DOMAIN_SETUP) - .identifier(domainName) - .caption(asset.getCaption() != null ? asset.getCaption() : domainName) - .parentAsset(ref(HsHostingAssetRealEntity.class, asset.getParentAssetUuid())) - .alarmContact(ref(HsOfficeContactRealEntity.class, asset.getAlarmContactUuid())) - .subHostingAssets( - standardMapper.mapList(getSubHostingAssetResources(), HsHostingAssetRealEntity.class) - ) - .build(); - } - - private HsHostingAssetRealEntity createDomainHttpSetupAssetEntity( - final List subHostingAssetResources, - final String domainName, - final HsHostingAssetRealEntity domainSetupAsset) { - final var domainHttpSetupAssetResource = subHostingAssetResources.stream() - .filter(ha -> ha.getType() == HsHostingAssetTypeResource.DOMAIN_HTTP_SETUP) - .findFirst().orElseThrow(() -> new ValidationException( - domainName + ": missing target unix user (assignedToHostingAssetUuid) for DOMAIN_HTTP_SETUP ")); - final var domainHttpSetupAsset = domainSetupAsset.getSubHostingAssets() - .stream() - .filter(sha -> sha.getType() == DOMAIN_HTTP_SETUP) - .findFirst() - .orElseThrow(); - domainHttpSetupAsset.setParentAsset(domainSetupAsset); - final var assignedToUnixUserAssetX = - emw.find(HsHostingAssetRealEntity.class, domainHttpSetupAssetResource.getAssignedToAssetUuid()); - domainHttpSetupAsset.setAssignedToAsset(assignedToUnixUserAssetX); - return domainHttpSetupAsset; - } - - private void createDomainSubSetupAssetEntity( - final HsHostingAssetRealEntity domainSetupAsset, - final HsHostingAssetType subAssetType, - final Function, HsHostingAssetRealEntityBuilder> builderTransformer) { - final var resourceType = HsHostingAssetTypeResource.valueOf(subAssetType.name()); - if (getSubHostingAssetResources().stream().noneMatch(ha -> ha.getType() == resourceType)) { - final var subAssetEntity = builderTransformer.apply( - HsHostingAssetRealEntity.builder() - .type(HsHostingAssetType.valueOf(subAssetType.name())) - .parentAsset(domainSetupAsset)) - .build(); - domainSetupAsset.getSubHostingAssets().add(subAssetEntity); - } - } - - private String getDomainName() { - return asset.getIdentifier(); - } - - private List getSubHostingAssetResources() { - return asset.getSubHostingAssets(); - } - - @Override - protected void persist(final HsHostingAsset newHostingAsset) { - super.persist(newHostingAsset); - newHostingAsset.getSubHostingAssets().forEach(super::persist); - } - } -} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/DomainSetupHostingAssetFactory.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/DomainSetupHostingAssetFactory.java new file mode 100644 index 00000000..37045f93 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/DomainSetupHostingAssetFactory.java @@ -0,0 +1,128 @@ +package net.hostsharing.hsadminng.hs.hosting.asset.factories; + +import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetAutoInsertResource; +import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetSubInsertResource; +import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetTypeResource; +import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity; +import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset; +import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity; +import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType; +import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; +import net.hostsharing.hsadminng.mapper.StandardMapper; +import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; + +import jakarta.validation.ValidationException; +import java.net.IDN; +import java.util.List; +import java.util.function.Function; + +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_HTTP_SETUP; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_MBOX_SETUP; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP; + +public class DomainSetupHostingAssetFactory extends HostingAssetFactory { + + public DomainSetupHostingAssetFactory( + final EntityManagerWrapper emw, + final HsBookingItemRealEntity newBookingItemRealEntity, + final HsHostingAssetAutoInsertResource asset, + final StandardMapper standardMapper) { + super(emw, newBookingItemRealEntity, asset, standardMapper); + } + + @Override + protected HsHostingAsset create() { + final var domainSetupAsset = createDomainSetupAsset(getDomainName()); + + // TODO.legacy: as long as we need to be compatible, we always do all technical domain-setups + final var subHostingAssetResources = getSubHostingAssetResources(); + final var domainHttpSetupAsset = createDomainHttpSetupAssetEntity( + subHostingAssetResources, + getDomainName(), + domainSetupAsset); + final var assignedToUnixUserAsset = domainHttpSetupAsset.getAssignedToAsset(); + + // TODO.legacy: don't create DNS setup as long as we need to remain support legacy web-ui etc. + + createDomainSubSetupAssetEntity( + domainSetupAsset, + DOMAIN_MBOX_SETUP, + builder -> builder + .assignedToAsset(assignedToUnixUserAsset.getParentAsset()) + .identifier(getDomainName() + "|MBOX") + .caption("HTTP-Setup für " + IDN.toUnicode(getDomainName()))); + + createDomainSubSetupAssetEntity( + domainSetupAsset, + DOMAIN_SMTP_SETUP, + builder -> builder + .assignedToAsset(assignedToUnixUserAsset.getParentAsset()) + .identifier(getDomainName() + "|SMTP") + .caption("HTTP-Setup für " + IDN.toUnicode(getDomainName()))); + + return domainSetupAsset; + } + + private HsHostingAssetRealEntity createDomainSetupAsset(final String domainName) { + return HsHostingAssetRealEntity.builder() + .bookingItem(fromBookingItem) + .type(HsHostingAssetType.DOMAIN_SETUP) + .identifier(domainName) + .caption(asset.getCaption() != null ? asset.getCaption() : domainName) + .parentAsset(ref(HsHostingAssetRealEntity.class, asset.getParentAssetUuid())) + .alarmContact(ref(HsOfficeContactRealEntity.class, asset.getAlarmContactUuid())) + .subHostingAssets( + standardMapper.mapList(getSubHostingAssetResources(), HsHostingAssetRealEntity.class) + ) + .build(); + } + + private HsHostingAssetRealEntity createDomainHttpSetupAssetEntity( + final List subHostingAssetResources, + final String domainName, + final HsHostingAssetRealEntity domainSetupAsset) { + final var domainHttpSetupAssetResource = subHostingAssetResources.stream() + .filter(ha -> ha.getType() == HsHostingAssetTypeResource.DOMAIN_HTTP_SETUP) + .findFirst().orElseThrow(() -> new ValidationException( + domainName + ": missing target unix user (assignedToHostingAssetUuid) for DOMAIN_HTTP_SETUP ")); + final var domainHttpSetupAsset = domainSetupAsset.getSubHostingAssets() + .stream() + .filter(sha -> sha.getType() == DOMAIN_HTTP_SETUP) + .findFirst() + .orElseThrow(); + domainHttpSetupAsset.setParentAsset(domainSetupAsset); + final var assignedToUnixUserAsset = + emw.find(HsHostingAssetRealEntity.class, domainHttpSetupAssetResource.getAssignedToAssetUuid()); + domainHttpSetupAsset.setAssignedToAsset(assignedToUnixUserAsset); + return domainHttpSetupAsset; + } + + private void createDomainSubSetupAssetEntity( + final HsHostingAssetRealEntity domainSetupAsset, + final HsHostingAssetType subAssetType, + final Function, HsHostingAssetRealEntity.HsHostingAssetRealEntityBuilder> builderTransformer) { + final var resourceType = HsHostingAssetTypeResource.valueOf(subAssetType.name()); + if (getSubHostingAssetResources().stream().noneMatch(ha -> ha.getType() == resourceType)) { + final var subAssetEntity = builderTransformer.apply( + HsHostingAssetRealEntity.builder() + .type(HsHostingAssetType.valueOf(subAssetType.name())) + .parentAsset(domainSetupAsset)) + .build(); + domainSetupAsset.getSubHostingAssets().add(subAssetEntity); + } + } + + private String getDomainName() { + return asset.getIdentifier(); + } + + private List getSubHostingAssetResources() { + return asset.getSubHostingAssets(); + } + + @Override + protected void persist(final HsHostingAsset newHostingAsset) { + super.persist(newHostingAsset); + newHostingAsset.getSubHostingAssets().forEach(super::persist); + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HostingAssetFactory.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HostingAssetFactory.java new file mode 100644 index 00000000..cf30a5b0 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HostingAssetFactory.java @@ -0,0 +1,45 @@ +package net.hostsharing.hsadminng.hs.hosting.asset.factories; + +import lombok.RequiredArgsConstructor; +import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetAutoInsertResource; +import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity; +import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset; +import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor; +import net.hostsharing.hsadminng.mapper.StandardMapper; +import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; + +import java.util.UUID; + +@RequiredArgsConstructor +abstract class HostingAssetFactory { + + final EntityManagerWrapper emw; + final HsBookingItemRealEntity fromBookingItem; + final HsHostingAssetAutoInsertResource asset; + final StandardMapper standardMapper; + + protected abstract HsHostingAsset create(); + + public String performSaveProcess() { + final var newHostingAsset = create(); + try { + persist(newHostingAsset); + return null; + } catch (final Exception e) { + return e.getMessage(); + } + } + + protected void persist(final HsHostingAsset newHostingAsset) { + new HostingAssetEntitySaveProcessor(emw, newHostingAsset) + .preprocessEntity() + .validateEntity() + .prepareForSave() + .save() + .validateContext(); + } + + protected T ref(final Class entityClass, final UUID uuid) { + return uuid != null ? emw.getReference(entityClass, uuid) : null; + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HsBookingItemCreatedListener.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HsBookingItemCreatedListener.java new file mode 100644 index 00000000..3143c841 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HsBookingItemCreatedListener.java @@ -0,0 +1,40 @@ +package net.hostsharing.hsadminng.hs.hosting.asset.factories; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetAutoInsertResource; +import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedAppEvent; +import net.hostsharing.hsadminng.mapper.StandardMapper; +import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +@Component +public class HsBookingItemCreatedListener implements ApplicationListener { + + @Autowired + private EntityManagerWrapper emw; + + @Autowired + private ObjectMapper jsonMapper; + + @Autowired + private StandardMapper standardMapper; + + @Override + @SneakyThrows + public void onApplicationEvent(final BookingItemCreatedAppEvent event) { + final var newBookingItemRealEntity = event.getEntity().getBookingItem(); + final var asset = jsonMapper.readValue(event.getEntity().getAssetJson(), HsHostingAssetAutoInsertResource.class); + final var factory = switch (newBookingItemRealEntity.getType()) { + case PRIVATE_CLOUD, CLOUD_SERVER, MANAGED_SERVER -> null; // for now, no automatic HostingAsset possible + case MANAGED_WEBSPACE -> null; // TODO.impl: implement ManagedWebspace HostingAsset creation, where possible + case DOMAIN_SETUP -> new DomainSetupHostingAssetFactory(emw, newBookingItemRealEntity, asset, standardMapper); + }; + if (factory != null) { + event.getEntity().setStatusMessage(factory.performSaveProcess()); + emw.persist(event.getEntity()); // TODO.impl: once we implement retry, we might need merge + } + } +}