You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by rm...@apache.org on 2020/12/16 13:33:21 UTC
[openwebbeans] branch master updated: [OWB-1357] skip extension
events resolution when there is no observer for them
This is an automated email from the ASF dual-hosted git repository.
rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openwebbeans.git
The following commit(s) were added to refs/heads/master by this push:
new cd25746 [OWB-1357] skip extension events resolution when there is no observer for them
cd25746 is described below
commit cd2574623f7dbfd00c0eb0439bc1042b29b9f52d
Author: Romain Manni-Bucau <rm...@gmail.com>
AuthorDate: Wed Dec 16 14:33:14 2020 +0100
[OWB-1357] skip extension events resolution when there is no observer for them
---
.../org/apache/webbeans/config/BeansDeployer.java | 5 +-
.../apache/webbeans/event/NotificationManager.java | 284 ++++++++++++++++++++-
.../test/portable/events/PortableEventTest.java | 1 -
3 files changed, 285 insertions(+), 5 deletions(-)
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java b/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java
index 20489b1..a7b2337 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java
@@ -309,7 +309,10 @@ public class BeansDeployer
// activate InjectionResolver cache now
webBeansContext.getBeanManagerImpl().getInjectionResolver().setStartup(false);
-
+
+ // drop no more needed memory data
+ webBeansContext.getNotificationManager().afterStart();
+
validateAlternatives(beanAttributesPerBda);
validateInjectionPoints();
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java b/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java
index 7c7ae7c..dede48e 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java
@@ -33,6 +33,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
@@ -45,6 +46,7 @@ import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Stream;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.NotificationOptions;
@@ -61,7 +63,17 @@ import javax.enterprise.inject.spi.EventContext;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ObserverMethod;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import javax.enterprise.inject.spi.ProcessBean;
+import javax.enterprise.inject.spi.ProcessBeanAttributes;
+import javax.enterprise.inject.spi.ProcessInjectionPoint;
+import javax.enterprise.inject.spi.ProcessInjectionTarget;
+import javax.enterprise.inject.spi.ProcessManagedBean;
+import javax.enterprise.inject.spi.ProcessObserverMethod;
import javax.enterprise.inject.spi.ProcessProducer;
+import javax.enterprise.inject.spi.ProcessProducerField;
+import javax.enterprise.inject.spi.ProcessProducerMethod;
+import javax.enterprise.inject.spi.ProcessSyntheticBean;
+import javax.enterprise.inject.spi.ProcessSyntheticObserverMethod;
import org.apache.webbeans.component.AbstractOwbBean;
import org.apache.webbeans.config.OWBLogConst;
@@ -82,6 +94,9 @@ import org.apache.webbeans.util.ClassUtil;
import org.apache.webbeans.util.GenericsUtil;
import org.apache.webbeans.util.WebBeansUtil;
+import static java.util.Collections.emptyList;
+import static java.util.stream.Collectors.toMap;
+
public final class NotificationManager
{
private final Map<Type, Set<ObserverMethod<?>>> observers = new ConcurrentHashMap<>();
@@ -112,12 +127,40 @@ public final class NotificationManager
}
};
+ // idea is to be able to skip O(n) events in favor of an algorithm closer to O(1) impl
+ // statistically, it is not rare to not use all these events so we enable to skip most of them
+ private Map<Type, Set<ObserverMethod<?>>> processAnnotatedTypeObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processBeanAttributesObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processInjectionTargetObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processManagedBeanObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processBeanObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processInjectionPointObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processObserverMethodObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processProducerObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processProducerFieldObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processProducerMethodObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processSyntheticBeanObservers;
+ private Map<Type, Set<ObserverMethod<?>>> processSyntheticObserverMethodObservers;
+
public NotificationManager(WebBeansContext webBeansContext)
{
this.webBeansContext = webBeansContext;
this.defaultNotificationOptions = NotificationOptions.ofExecutor(getDefaultExecutor());
}
+ public void afterStart()
+ {
+ Stream.of(
+ processAnnotatedTypeObservers, processBeanAttributesObservers,
+ processInjectionTargetObservers, processManagedBeanObservers,
+ processBeanObservers, processInjectionPointObservers,
+ processObserverMethodObservers, processProducerObservers,
+ processProducerFieldObservers, processProducerMethodObservers,
+ processSyntheticBeanObservers, processSyntheticObserverMethodObservers)
+ .filter(Objects::nonNull)
+ .forEach(Map::clear);
+ }
+
private Executor getDefaultExecutor()
{
// here it would be nice to support to use a produced bean like @Named("openwebbeansCdiExecutor")
@@ -189,6 +232,177 @@ public final class NotificationManager
public <T> Collection<ObserverMethod<? super T>> resolveObservers(T event, EventMetadataImpl metadata, boolean isLifecycleEvent)
{
+ if (isLifecycleEvent) // goal here is to skip any resolution if not needed
+ {
+ if (event instanceof ProcessAnnotatedType)
+ {
+ if (processAnnotatedTypeObservers == null)
+ {
+ processAnnotatedTypeObservers = findObservers(ProcessAnnotatedType.class);
+ }
+ if (processAnnotatedTypeObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessManagedBean)
+ {
+ if (processManagedBeanObservers == null)
+ {
+ processManagedBeanObservers = findObservers(ProcessManagedBean.class);
+ if (processBeanObservers == null)
+ {
+ processBeanObservers = findObservers(ProcessBean.class);
+ }
+ processBeanObservers.forEach((k, v) -> processManagedBeanObservers
+ .computeIfAbsent(k, it -> new HashSet<>())
+ .addAll(v));
+ }
+ if (processManagedBeanObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessProducerField)
+ {
+ if (processProducerFieldObservers == null)
+ {
+ processProducerFieldObservers = findObservers(ProcessProducerField.class);
+ if (processBeanObservers == null)
+ {
+ processBeanObservers = findObservers(ProcessBean.class);
+ }
+ processBeanObservers.forEach((k, v) -> processProducerFieldObservers
+ .computeIfAbsent(k, it -> new HashSet<>())
+ .addAll(v));
+ }
+ if (processProducerFieldObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessProducerMethod)
+ {
+ if (processProducerMethodObservers == null)
+ {
+ processProducerMethodObservers = findObservers(ProcessProducerMethod.class);
+ if (processBeanObservers == null)
+ {
+ processBeanObservers = findObservers(ProcessBean.class);
+ }
+ processBeanObservers.forEach((k, v) -> processProducerMethodObservers
+ .computeIfAbsent(k, it -> new HashSet<>())
+ .addAll(v));
+ }
+ if (processProducerMethodObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessSyntheticBean)
+ {
+ if (processSyntheticBeanObservers == null)
+ {
+ processSyntheticBeanObservers = findObservers(ProcessSyntheticBean.class);
+ if (processBeanObservers == null)
+ {
+ processBeanObservers = findObservers(ProcessBean.class);
+ }
+ processBeanObservers.forEach((k, v) -> processSyntheticBeanObservers
+ .computeIfAbsent(k, it -> new HashSet<>())
+ .addAll(v));
+ }
+ if (processSyntheticBeanObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessSyntheticObserverMethod)
+ {
+ if (processSyntheticObserverMethodObservers == null)
+ {
+ processSyntheticObserverMethodObservers = findObservers(ProcessSyntheticObserverMethod.class);
+ if (processObserverMethodObservers == null)
+ {
+ processObserverMethodObservers = findObservers(ProcessObserverMethod.class);
+ }
+ processObserverMethodObservers.forEach((k, v) -> processSyntheticObserverMethodObservers
+ .computeIfAbsent(k, it -> new HashSet<>())
+ .addAll(v));
+ }
+ if (processSyntheticObserverMethodObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessBean)
+ {
+ if (processBeanObservers == null)
+ {
+ processBeanObservers = findObservers(ProcessBean.class);
+ }
+ if (processBeanObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessBeanAttributes)
+ {
+ if (processBeanAttributesObservers == null)
+ {
+ processBeanAttributesObservers = findObservers(ProcessBeanAttributes.class);
+ }
+ if (processBeanAttributesObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessInjectionTarget)
+ {
+ if (processInjectionTargetObservers == null)
+ {
+ processInjectionTargetObservers = findObservers(ProcessInjectionTarget.class);
+ }
+ if (processInjectionTargetObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessInjectionPoint)
+ {
+ if (processInjectionPointObservers == null)
+ {
+ processInjectionPointObservers = findObservers(ProcessInjectionPoint.class);
+ }
+ if (processInjectionPointObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessObserverMethod)
+ {
+ if (processObserverMethodObservers == null)
+ {
+ processObserverMethodObservers = findObservers(ProcessObserverMethod.class);
+ }
+ if (processObserverMethodObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ else if (event instanceof ProcessProducer)
+ {
+ if (processProducerObservers == null)
+ {
+ processProducerObservers = findObservers(ProcessProducer.class);
+ }
+ if (processProducerObservers.isEmpty())
+ {
+ return emptyList();
+ }
+ }
+ // note: don't forget to update filterByExtensionEventType method too
+ }
Type eventType = metadata.validatedType();
Collection<ObserverMethod<? super T>> observersMethods = filterByQualifiers(
filterByType(event, eventType, isLifecycleEvent), metadata.getQualifiers());
@@ -197,8 +411,7 @@ public final class NotificationManager
{
observersMethods = filterByWithAnnotations(observersMethods, ((ProcessAnnotatedType) event).getAnnotatedType());
}
-
- if (!isLifecycleEvent && observersMethods.isEmpty())
+ else if (!isLifecycleEvent && observersMethods.isEmpty())
{
//this check for the TCK is only needed if no observer was found
EventUtil.checkEventBindings(webBeansContext, metadata.getQualifiers());
@@ -367,7 +580,61 @@ public final class NotificationManager
{
Class<?> eventClass = ClassUtil.getClazz(eventType);
Set<ObserverMethod<? super T>> matching = new HashSet<>();
- Set<Type> keySet = observers.keySet();
+ final Map<Type, Set<ObserverMethod<?>>> sourceMap;
+ if (event instanceof ProcessAnnotatedType) // check resolveObservers
+ {
+ sourceMap = processAnnotatedTypeObservers;
+ }
+ else if (event instanceof ProcessSyntheticObserverMethod)
+ {
+ sourceMap = processSyntheticObserverMethodObservers;
+ }
+ else if (event instanceof ProcessObserverMethod)
+ {
+ sourceMap = processObserverMethodObservers;
+ }
+ else if (event instanceof ProcessProducerField)
+ {
+ sourceMap = processProducerFieldObservers;
+ }
+ else if (event instanceof ProcessProducerMethod)
+ {
+ sourceMap = processProducerMethodObservers;
+ }
+ else if (event instanceof ProcessSyntheticBean)
+ {
+ sourceMap = processSyntheticBeanObservers;
+ }
+ else if (event instanceof ProcessProducer)
+ {
+ sourceMap = processProducerObservers;
+ }
+ else if (event instanceof ProcessManagedBean)
+ {
+ sourceMap = processManagedBeanObservers;
+ }
+ else if (event instanceof ProcessBean)
+ {
+ sourceMap = processBeanObservers;
+ }
+ else if (event instanceof ProcessBeanAttributes)
+ {
+ sourceMap = processBeanAttributesObservers;
+ }
+ else if (event instanceof ProcessInjectionTarget)
+ {
+ sourceMap = processInjectionTargetObservers;
+ }
+ else if (event instanceof ProcessInjectionPoint)
+ {
+ sourceMap = processInjectionPointObservers;
+ }
+ else
+ {
+ sourceMap = observers;
+ }
+
+ Set<Type> keySet = sourceMap.keySet();
for (Type type : keySet)
{
Class<?> beanClass;
@@ -913,6 +1180,17 @@ public final class NotificationManager
return webBeansContext.getWebBeansUtil().isContainerEventType(paramType);
}
+ // for lifecycle parameterized events for now
+ private Map<Type, Set<ObserverMethod<?>>> findObservers(final Class<?> type)
+ {
+ return observers.entrySet().stream()
+ .filter(it -> {
+ final Class<?> keyType = ClassUtil.getClass(it.getKey());
+ return type.isAssignableFrom(keyType);
+ })
+ .collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
+ }
+
// this behaves as a future aggregator, we don't strictly need to represent it but found it more expressive
private static final class CDICompletionFuture<T> extends CompletableFuture<T>
{
diff --git a/webbeans-impl/src/test/java/org/apache/webbeans/test/portable/events/PortableEventTest.java b/webbeans-impl/src/test/java/org/apache/webbeans/test/portable/events/PortableEventTest.java
index eef8b13..b2103d8 100644
--- a/webbeans-impl/src/test/java/org/apache/webbeans/test/portable/events/PortableEventTest.java
+++ b/webbeans-impl/src/test/java/org/apache/webbeans/test/portable/events/PortableEventTest.java
@@ -79,7 +79,6 @@ public class PortableEventTest extends AbstractUnitTest
}
@Test
-
public void testRawTypeExtension()
{
Collection<String> beanXmls = new ArrayList<String>();