diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedAppEvent.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedAppEvent.java new file mode 100644 index 00000000..1e65d914 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedAppEvent.java @@ -0,0 +1,20 @@ +package net.hostsharing.hsadminng.hs.booking.item; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +import jakarta.validation.constraints.NotNull; + +@Getter +public class BookingItemCreatedAppEvent extends ApplicationEvent { + + private BookingItemCreatedEventEntity entity; + + public BookingItemCreatedAppEvent( + @NotNull final HsBookingItemController source, + @NotNull final HsBookingItemRealEntity newBookingItem, + final String assetJson) { + super(source); + this.entity = new BookingItemCreatedEventEntity(newBookingItem, assetJson); + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEvent.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEvent.java deleted file mode 100644 index 1b723353..00000000 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEvent.java +++ /dev/null @@ -1,60 +0,0 @@ -package net.hostsharing.hsadminng.hs.booking.item; - -import lombok.Getter; -import org.springframework.context.ApplicationEvent; - -import jakarta.validation.constraints.NotNull; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -@Getter -public class BookingItemCreatedEvent extends ApplicationEvent { - - private static final Map events = new HashMap<>(); // FIXME: use DB table - - static BookingItemCreatedEvent of(final HsBookingItemRealEntity bookingItem) { - return events.get(bookingItem.getUuid()); - } - - @Getter - public static class Status { - - private final String message; - - private Status(final String message) { - this.message = message; - } - - public static Status finished() { - return new Status(null); - } - - public static Status failed(final String errorMessage) { - return new Status(errorMessage); - } - - boolean isFinished() { - return message == null; - } - } - - private final @NotNull UUID bookingItemUuid; - private final @NotNull String assetJson; - - private Status status; - - public BookingItemCreatedEvent( - @NotNull final HsBookingItemController source, - @NotNull final HsBookingItem newBookingItem, - final String assetJson) { - super(source); - this.bookingItemUuid = newBookingItem.getUuid(); - this.assetJson = assetJson; - } - - public void setStatus(final Status status) { - this.status = status; - events.put(bookingItemUuid, this); - } -} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEventEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEventEntity.java new file mode 100644 index 00000000..03b39d88 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEventEntity.java @@ -0,0 +1,60 @@ +package net.hostsharing.hsadminng.hs.booking.item; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; +import jakarta.persistence.Version; +import jakarta.validation.constraints.NotNull; +import java.util.UUID; + + + +@Entity +@Table(schema = "hs_booking", name = "item_created_event") +@SuperBuilder(toBuilder = true) +@Getter +@NoArgsConstructor +public class BookingItemCreatedEventEntity { + @Id + @Column(name="bookingitemuuid") + private UUID id; + + @MapsId + @ManyToOne(optional = false) + @JoinColumn(name = "bookingitemuuid", nullable = false) + private HsBookingItemRealEntity bookingItem; + + @Version + private int version; + + @Column(name = "assetjson") + private String assetJson; + + @Setter + @Column(name = "statusmessage") + private String statusMessage; + + @Setter + @Column + private boolean completed; + + public void setBookingItem(HsBookingItemRealEntity bookingItem) { + this.bookingItem = bookingItem; + } + + public BookingItemCreatedEventEntity( + @NotNull final HsBookingItemRealEntity newBookingItem, + final String assetJson) { + this.bookingItem = newBookingItem; + this.assetJson = assetJson; + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEventRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEventRepository.java new file mode 100644 index 00000000..e36bda61 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/BookingItemCreatedEventRepository.java @@ -0,0 +1,12 @@ +package net.hostsharing.hsadminng.hs.booking.item; + +import org.springframework.data.repository.Repository; + +import java.util.UUID; + +public interface BookingItemCreatedEventRepository extends Repository { + + BookingItemCreatedEventEntity save(HsBookingItemRealEntity current); + + BookingItemCreatedEventEntity findByBookingItem(HsBookingItemRealEntity newBookingItem); +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemController.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemController.java index 801fff0f..8a78ba2a 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemController.java @@ -83,8 +83,9 @@ public class HsBookingItemController implements HsBookingItemsApi { .revampProperties(); try { - applicationEventPublisher.publishEvent(new BookingItemCreatedEvent( - this, saveProcessor.getEntity(), jsonMapper.writeValueAsString(body.getAsset()))); + final var bookingItemRealEntity = em.getReference(HsBookingItemRealEntity.class, saveProcessor.getEntity().getUuid()); + applicationEventPublisher.publishEvent(new BookingItemCreatedAppEvent( + this, bookingItemRealEntity, jsonMapper.writeValueAsString(body.getAsset()))); } catch (JsonProcessingException e) { throw new RuntimeException(e); } 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 index 4312f5d3..b4eb59df 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsBookingItemCreatedListener.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsBookingItemCreatedListener.java @@ -5,8 +5,7 @@ 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.HsHostingAssetTypeResource; -import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedEvent; -import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedEvent.Status; +import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedAppEvent; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity; import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; @@ -28,7 +27,7 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMA import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP; @Component -public class HsBookingItemCreatedListener implements ApplicationListener { +public class HsBookingItemCreatedListener implements ApplicationListener { @Autowired private EntityManagerWrapper emw; @@ -41,19 +40,19 @@ public class HsBookingItemCreatedListener implements ApplicationListener null; case CLOUD_SERVER -> null; case MANAGED_SERVER -> null; - case MANAGED_WEBSPACE -> null; + case MANAGED_WEBSPACE -> null; // TODO.impl: implement ManagedWebspace HostingAsset creation, where possible case DOMAIN_SETUP -> new DomainSetupHostingAssetFactory(newBookingItemRealEntity, asset); }; if (factory != null) { - event.setStatus(factory.performSaveProcess()); + event.getEntity().setStatusMessage(factory.performSaveProcess()); + emw.persist(event.getEntity()); // TODO.impl: once we implement retry, we might need merge } } @@ -71,23 +70,23 @@ public class HsBookingItemCreatedListener implements ApplicationListener bi.getDirectValue("domainName", String.class)) .isEqualTo("example.org"); - final var status = BookingItemCreatedEvent.of(newBookingItem); - assertThat(status.getStatus().getMessage()) + final var event = bookingItemCreationEventRepo.findByBookingItem(newBookingItem); + assertThat(event.getStatusMessage()) .isEqualTo("[[DNS] no TXT record 'Hostsharing-domain-setup-verification-code=just-a-fake-verification-code' found for domain name 'example.org' (nor in its super-domain)]"); // but the related HostingAsset did not get created @@ -565,6 +569,13 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup }).assertSuccessful().returnedValue(); } + @AfterEach + void cleanupEventEntities() { + jpaAttempt.transacted(() -> { + em.createQuery("delete from BookingItemCreatedEventEntity").executeUpdate(); + }).assertSuccessful(); + } + private Map.Entry resource(final String key, final Object value) { return entry(key, value); }