use of javax.enterprise.event.NotificationOptions in project core by weld.
the class ObserverNotifier method notifyAsyncObservers.
protected <T, U extends T> CompletionStage<U> notifyAsyncObservers(List<ObserverMethod<? super T>> observers, U event, EventMetadata metadata, Executor executor, NotificationOptions options) {
if (executor == null) {
executor = asyncEventExecutor;
}
if (observers.isEmpty()) {
return AsyncEventDeliveryStage.completed(event, executor);
}
// We should always initialize and validate all notification options first
final NotificationMode mode = initModeOption(options.get(WeldNotificationOptions.MODE));
final Long timeout = initTimeoutOption(options.get(WeldNotificationOptions.TIMEOUT));
final Consumer<Runnable> securityContextActionConsumer = securityServices.getSecurityContextAssociator();
final ObserverExceptionHandler exceptionHandler;
CompletableFuture<U> completableFuture;
if (observers.size() > 1 && NotificationMode.PARALLEL.equals(mode)) {
// Attempt to notify async observers in parallel
exceptionHandler = new CollectingExceptionHandler(new CopyOnWriteArrayList<>());
List<CompletableFuture<T>> completableFutures = new ArrayList<>(observers.size());
for (ObserverMethod<? super T> observer : observers) {
completableFutures.add(CompletableFuture.supplyAsync(createSupplier(securityContextActionConsumer, event, metadata, exceptionHandler, false, () -> {
notifyAsyncObserver(observer, event, metadata, exceptionHandler);
}), executor));
}
completableFuture = CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[] {})).thenApply((ignoredVoid) -> {
handleExceptions(exceptionHandler);
return event;
});
} else {
// Async observers are notified serially in a single worker thread
exceptionHandler = new CollectingExceptionHandler();
completableFuture = CompletableFuture.supplyAsync(createSupplier(securityContextActionConsumer, event, metadata, exceptionHandler, true, () -> {
for (ObserverMethod<? super T> observer : observers) {
notifyAsyncObserver(observer, event, metadata, exceptionHandler);
}
}), executor);
}
// If NotificationOptionKeys.TIMEOUT is set, we will trigger the counter and use CompletableFuture.anyOf()
if (timeout != null) {
completableFuture = CompletableFuture.anyOf(completableFuture, startTimer(timeout)).thenApply((ignoredObject) -> event);
}
return new AsyncEventDeliveryStage<>(completableFuture, executor);
}
use of javax.enterprise.event.NotificationOptions in project core by weld.
the class NotificationTimeoutTest method testMultipleObserverParallelNotificationTimeout.
@Test
public void testMultipleObserverParallelNotificationTimeout() throws InterruptedException {
SUCCESSION_OF_EVENTS.clear();
try (WeldContainer container = new Weld().initialize()) {
BlockingQueue<Throwable> synchronizer = new LinkedBlockingQueue<>();
CountDownLatch countdown = new CountDownLatch(2);
NotificationOptions options = NotificationOptions.builder().set(WeldNotificationOptions.TIMEOUT, "2000").set(WeldNotificationOptions.MODE, WeldNotificationOptions.NotificationMode.PARALLEL).build();
container.event().select(CountDownLatch.class).fireAsync(countdown, options).exceptionally((Throwable t) -> {
// handle TimeoutException we got here
SUCCESSION_OF_EVENTS.add("Timeout");
synchronizer.add(t);
return null;
});
Throwable fromSynchronizer = synchronizer.poll(5, TimeUnit.SECONDS);
Assert.assertNotNull(fromSynchronizer);
Assert.assertTrue(fromSynchronizer.getCause().toString().contains(TimeoutException.class.getSimpleName()));
// wait for the observers to finish their jobs
countdown.await();
// with parallel execution, we can only assert that all observers were notified (the order might differ)
Assert.assertTrue(SUCCESSION_OF_EVENTS.size() == 3);
Assert.assertTrue(SUCCESSION_OF_EVENTS.containsAll(getExpectedListOfEvents()));
}
}
Aggregations