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 <rmannibu...@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>();

Reply via email to