From e877bcce3179305e57ae78b8f6c18ba9334c264e Mon Sep 17 00:00:00 2001 From: Simon Urli Date: Tue, 27 Feb 2024 10:48:46 +0100 Subject: [PATCH] XWIKI-21809: ClassCastException in DefaultEventConverterManager on a cluster environment (#2929) * Some task output is Optional and we never want the Optional in the notification data: we do want what the Optional contains. * Prevent entirely notification to be sent if output is Optional and return is empty --- .../AbstractAsynchronousEventStore.java | 66 +++++++++++-------- .../internal/AsynchronousEventStoreTest.java | 21 ++++++ 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-eventstream/xwiki-platform-eventstream-api/src/main/java/org/xwiki/eventstream/internal/AbstractAsynchronousEventStore.java b/xwiki-platform-core/xwiki-platform-eventstream/xwiki-platform-eventstream-api/src/main/java/org/xwiki/eventstream/internal/AbstractAsynchronousEventStore.java index 260e6e52d969..e82b10a47a5c 100644 --- a/xwiki-platform-core/xwiki-platform-eventstream/xwiki-platform-eventstream-api/src/main/java/org/xwiki/eventstream/internal/AbstractAsynchronousEventStore.java +++ b/xwiki-platform-core/xwiki-platform-eventstream/xwiki-platform-eventstream-api/src/main/java/org/xwiki/eventstream/internal/AbstractAsynchronousEventStore.java @@ -439,41 +439,53 @@ private void complete(EventStoreTask task, O output) task.future.complete(output); // Notify event listeners - switch (task.type) { - case DELETE_EVENT: - this.observation.notify(new EventStreamDeletedEvent(), task.output); - break; + Object notificationOuput = task.output; + boolean skipNotify = false; + if (task.output instanceof Optional) { + Optional optionalOutput = (Optional) task.output; + if (optionalOutput.isPresent()) { + notificationOuput = optionalOutput.get(); + } else { + skipNotify = true; + } + } + if (!skipNotify) { + switch (task.type) { + case DELETE_EVENT: + this.observation.notify(new EventStreamDeletedEvent(), notificationOuput); + break; - case DELETE_EVENT_BY_ID: - this.observation.notify(new EventStreamDeletedEvent(), task.output); - break; + case DELETE_EVENT_BY_ID: + this.observation.notify(new EventStreamDeletedEvent(), notificationOuput); + break; - case SAVE_EVENT: - this.observation.notify(new EventStreamAddedEvent(), task.output); - break; + case SAVE_EVENT: + this.observation.notify(new EventStreamAddedEvent(), notificationOuput); + break; - case DELETE_STATUS: - this.observation.notify(new EventStatusDeletedEvent(), task.output); - break; + case DELETE_STATUS: + this.observation.notify(new EventStatusDeletedEvent(), notificationOuput); + break; - case DELETE_STATUSES: - this.observation.notify(new EventStatusDeletedEvent(), null); - break; + case DELETE_STATUSES: + this.observation.notify(new EventStatusDeletedEvent(), null); + break; - case SAVE_STATUS: - this.observation.notify(new EventStatusAddOrUpdatedEvent(), task.output); - break; + case SAVE_STATUS: + this.observation.notify(new EventStatusAddOrUpdatedEvent(), notificationOuput); + break; - case DELETE_MAIL_ENTITY: - this.observation.notify(new MailEntityDeleteEvent(), task.output); - break; + case DELETE_MAIL_ENTITY: + this.observation.notify(new MailEntityDeleteEvent(), notificationOuput); + break; - case SAVE_MAIL_ENTITY: - this.observation.notify(new MailEntityAddedEvent(), task.output); - break; + case SAVE_MAIL_ENTITY: + this.observation.notify(new MailEntityAddedEvent(), notificationOuput); + break; - default: - break; + default: + break; + } } } diff --git a/xwiki-platform-core/xwiki-platform-eventstream/xwiki-platform-eventstream-api/src/test/java/org/xwiki/eventstream/internal/AsynchronousEventStoreTest.java b/xwiki-platform-core/xwiki-platform-eventstream/xwiki-platform-eventstream-api/src/test/java/org/xwiki/eventstream/internal/AsynchronousEventStoreTest.java index 3b3ee40725e9..2e9f78aa4e38 100644 --- a/xwiki-platform-core/xwiki-platform-eventstream/xwiki-platform-eventstream-api/src/test/java/org/xwiki/eventstream/internal/AsynchronousEventStoreTest.java +++ b/xwiki-platform-core/xwiki-platform-eventstream/xwiki-platform-eventstream-api/src/test/java/org/xwiki/eventstream/internal/AsynchronousEventStoreTest.java @@ -37,9 +37,14 @@ import org.xwiki.eventstream.EventSearchResult; import org.xwiki.eventstream.EventStatus; import org.xwiki.eventstream.EventStreamException; +import org.xwiki.eventstream.events.EventStreamAddedEvent; +import org.xwiki.eventstream.events.MailEntityAddedEvent; +import org.xwiki.eventstream.events.MailEntityDeleteEvent; +import org.xwiki.observation.ObservationManager; import org.xwiki.test.junit5.mockito.ComponentTest; import org.xwiki.test.junit5.mockito.InjectComponentManager; import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; import org.xwiki.test.mockito.MockitoComponentManager; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -47,6 +52,9 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; /** * Validate {@link AbstractAsynchronousEventStore}. @@ -265,6 +273,9 @@ protected Optional syncDeleteEvent(Event event) throws EventStreamExcepti @InjectMockComponents private TestAbstractAsynchronousEventStore store; + @MockComponent + private ObservationManager observation; + private DefaultEvent event(String id) { DefaultEvent event = new DefaultEvent(); @@ -404,12 +415,22 @@ void mailentity() throws InterruptedException, ExecutionException, EventStreamEx assertSame(status21, this.store.events.get(event2.getId()).mailstatuses.get(status21.getEntityId())); assertSame(status24, this.store.events.get(event2.getId()).mailstatuses.get(status24.getEntityId())); + verify(this.observation).notify(any(EventStreamAddedEvent.class), eq(event1)); + verify(this.observation).notify(any(EventStreamAddedEvent.class), eq(event2)); + verify(this.observation).notify(any(MailEntityAddedEvent.class), eq(status11)); + verify(this.observation).notify(any(MailEntityAddedEvent.class), eq(status13)); + verify(this.observation).notify(any(MailEntityAddedEvent.class), eq(status21)); + verify(this.observation).notify(any(MailEntityAddedEvent.class), eq(status24)); + + this.store.deleteMailEntityEvent(status11).get(); assertNull(this.store.events.get(event1.getId()).mailstatuses.get(status11.getEntityId())); assertSame(status13, this.store.events.get(event1.getId()).mailstatuses.get(status13.getEntityId())); assertSame(status21, this.store.events.get(event2.getId()).mailstatuses.get(status21.getEntityId())); assertSame(status24, this.store.events.get(event2.getId()).mailstatuses.get(status24.getEntityId())); + + verify(this.observation).notify(any(MailEntityDeleteEvent.class), eq(status11)); } @Test