You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ta...@apache.org on 2020/04/14 13:15:17 UTC

[myfaces] branch master updated: MYFACES-4328 SystemEventListeners registered for a superclass is not invoked for childclass

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/master by this push:
     new e0fdeac  MYFACES-4328 SystemEventListeners registered for a superclass is not invoked for childclass
e0fdeac is described below

commit e0fdeac0c552c7ae83c63fe6bf470b882f4afa1d
Author: Thomas Andraschko <ta...@apache.org>
AuthorDate: Tue Apr 14 15:15:10 2020 +0200

    MYFACES-4328 SystemEventListeners registered for a superclass is not invoked for childclass
---
 .../myfaces/application/ApplicationImpl.java       | 214 +-----------
 .../application/ApplicationImplEventManager.java   | 363 +++++++++++++++++++++
 .../myfaces/application/_ApplicationUtils.java     | 222 -------------
 .../myfaces/application/ApplicationImplTest.java   |  34 +-
 .../event/GlobalPostAddToViewEventTestCase.java    |  51 ++-
 5 files changed, 432 insertions(+), 452 deletions(-)

diff --git a/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java b/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
index a62b405..faad42f 100755
--- a/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
@@ -74,14 +74,12 @@ import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
 import javax.faces.convert.DateTimeConverter;
 import javax.faces.convert.FacesConverter;
-import javax.faces.event.AbortProcessingException;
 import javax.faces.event.ActionListener;
 import javax.faces.event.ComponentSystemEventListener;
 import javax.faces.event.ListenerFor;
 import javax.faces.event.ListenersFor;
 import javax.faces.event.SystemEvent;
 import javax.faces.event.SystemEventListener;
-import javax.faces.event.SystemEventListenerHolder;
 import javax.faces.flow.FlowHandler;
 import javax.faces.render.ClientBehaviorRenderer;
 import javax.faces.render.RenderKit;
@@ -117,7 +115,6 @@ import org.apache.myfaces.config.element.Property;
 import org.apache.myfaces.config.element.ResourceBundle;
 import org.apache.myfaces.context.RequestViewContext;
 import org.apache.myfaces.context.RequestViewMetadata;
-import org.apache.myfaces.el.ELResolverBuilder;
 import org.apache.myfaces.el.ELResolverBuilderForFaces;
 import org.apache.myfaces.el.resolver.FacesCompositeELResolver;
 import org.apache.myfaces.el.resolver.FacesCompositeELResolver.Scope;
@@ -183,9 +180,8 @@ public class ApplicationImpl extends Application
 
     private final Map<String, Object> _validatorClassMap = new ConcurrentHashMap<>();
 
-    private final Map<Class<? extends SystemEvent>, SystemListenerEntry> _systemEventListenerClassMap
-            = new ConcurrentHashMap<>();
-
+    private ApplicationImplEventManager _eventManager;
+    
     private final Map<String, String> _defaultValidatorsIds = new HashMap<>();
     
     private volatile Map<String, String> _cachedDefaultValidatorsIds = null;
@@ -197,8 +193,6 @@ public class ApplicationImpl extends Application
 
     private Lazy<ELResolver> elResolver;
 
-    private ELResolverBuilder resolverBuilderForFaces;
-
     private ProjectStage _projectStage;
 
     private volatile boolean _firstRequestProcessed = false;
@@ -262,12 +256,13 @@ public class ApplicationImpl extends Application
         _actionListener = new ActionListenerImpl();
         _defaultRenderKitId = "HTML_BASIC";
         _stateManager = new StateManagerImpl();
-        _elContextListeners = new ArrayList<ELContextListener>();
+        _elContextListeners = new ArrayList<>();
         _resourceHandler = new ResourceHandlerImpl();
         _flowHandler = new FlowHandlerImpl();
         _searchExpressionHandler = new SearchExpressionHandlerImpl();
         _runtimeConfig = runtimeConfig;
         _myfacesConfig = MyfacesConfig.getCurrentInstance(getFacesContext());
+        _eventManager = new ApplicationImplEventManager();
 
         if (log.isLoggable(Level.FINEST))
         {
@@ -516,68 +511,13 @@ public class ApplicationImpl extends Application
     public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass,
                              Class<?> sourceBaseType, Object source)
     {
-        Assert.notNull(systemEventClass, "systemEventClass");
-        Assert.notNull(source, "source");
-        
-        //Call events only if event processing is enabled.
-        if (!facesContext.isProcessingEvents())
-        {
-            return;
-        }
-        
-        // spec: If this argument is null the return from source.getClass() must be used as the sourceBaseType. 
-        if (sourceBaseType == null)
-        {
-            sourceBaseType = source.getClass();
-        }
-        
-        try
-        {
-            SystemEvent event = null;
-            
-            // component attached listeners
-            if (source instanceof SystemEventListenerHolder)
-            {
-                SystemEventListenerHolder holder = (SystemEventListenerHolder) source;
-
-                // If the source argument implements SystemEventListenerHolder, call
-                // SystemEventListenerHolder.getListenersForEventClass(java.lang.Class) on it, passing the
-                // systemEventClass
-                // argument. If the list is not empty, perform algorithm traverseListenerList on the list.
-                event = _ApplicationUtils._traverseListenerList(
-                        facesContext, holder.getListenersForEventClass(systemEventClass),
-                        systemEventClass, source, event);
-            }
-
-            // view attached listeners
-            UIViewRoot viewRoot = facesContext.getViewRoot();
-            if (viewRoot != null)
-            {
-                event = _ApplicationUtils._traverseListenerListWithCopy(
-                        facesContext, viewRoot.getViewListenersForEventClass(systemEventClass), 
-                        systemEventClass, source, event);
-            }
-
-            // global listeners
-            SystemListenerEntry systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
-            if (systemListenerEntry != null)
-            {
-                systemListenerEntry.publish(facesContext, systemEventClass, sourceBaseType, source, event);
-            }
-        }
-        catch (AbortProcessingException e)
-        {
-            // If the act of invoking the processListener method causes an AbortProcessingException to be thrown,
-            // processing of the listeners must be aborted, no further processing of the listeners for this event must
-            // take place, and the exception must be logged with Level.SEVERE.
-            log.log(Level.SEVERE, "Event processing was aborted", e);
-        }
+        _eventManager.publishEvent(facesContext, systemEventClass, sourceBaseType, source);
     }
 
     @Override
     public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass, Object source)
     {
-        publishEvent(facesContext, systemEventClass, source.getClass(), source);
+        _eventManager.publishEvent(facesContext, systemEventClass, source);
     }
 
     @Override
@@ -856,48 +796,27 @@ public class ApplicationImpl extends Application
     @Override
     public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener)
     {
-        subscribeToEvent(systemEventClass, null, listener);
+        _eventManager.subscribeToEvent(systemEventClass, listener);
     }
 
     @Override
     public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass,
                                  SystemEventListener listener)
     {
-        Assert.notNull(systemEventClass, "systemEventClass");
-        Assert.notNull(listener, "listener");
-
-        SystemListenerEntry systemListenerEntry;
-        synchronized (_systemEventListenerClassMap)
-        {
-            systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
-            if (systemListenerEntry == null)
-            {
-                systemListenerEntry = new SystemListenerEntry();
-                _systemEventListenerClassMap.put(systemEventClass, systemListenerEntry);
-            }
-        }
-
-        systemListenerEntry.addListener(listener, sourceClass);
+        _eventManager.subscribeToEvent(systemEventClass, sourceClass, listener);
     }
     
     @Override
     public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener)
     {
-        unsubscribeFromEvent(systemEventClass, null, listener);
+        _eventManager.unsubscribeFromEvent(systemEventClass, listener);
     }
 
     @Override
     public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass,
                                      SystemEventListener listener)
     {
-        Assert.notNull(systemEventClass, "systemEventClass");
-        Assert.notNull(listener, "listener");
-
-        SystemListenerEntry systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
-        if (systemListenerEntry != null)
-        {
-            systemListenerEntry.removeListener(listener, sourceClass);
-        }
+        _eventManager.unsubscribeFromEvent(systemEventClass, sourceClass, listener);
     }
 
     @Override
@@ -2432,120 +2351,7 @@ public class ApplicationImpl extends Application
         }
         return _firstRequestProcessed;
     }
-    
-    private static class SystemListenerEntry
-    {
-        private List<SystemEventListener> _lstSystemEventListener;
-        private Map<Class<?>, List<SystemEventListener>> _sourceClassMap;
 
-        public SystemListenerEntry()
-        {
-        }
-
-        public void addListener(SystemEventListener listener)
-        {
-            assert listener != null;
-
-            addListenerNoDuplicate(getAnySourceListenersNotNull(), listener);
-        }
-
-        public void addListener(SystemEventListener listener, Class<?> source)
-        {
-            assert listener != null;
-
-            if (source == null)
-            {
-                addListener(listener);
-            }
-            else
-            {
-                addListenerNoDuplicate(getSpecificSourceListenersNotNull(source), listener);
-            }
-        }
-
-        public void removeListener(SystemEventListener listener)
-        {
-            assert listener != null;
-
-            if (_lstSystemEventListener != null)
-            {
-                _lstSystemEventListener.remove(listener);
-            }
-        }
-
-        public void removeListener(SystemEventListener listener, Class<?> sourceClass)
-        {
-            assert listener != null;
-
-            if (sourceClass == null)
-            {
-                removeListener(listener);
-            }
-            else
-            {
-                if (_sourceClassMap != null)
-                {
-                    List<SystemEventListener> listeners = _sourceClassMap.get(sourceClass);
-                    if (listeners != null)
-                    {
-                        listeners.remove(listener);
-                    }
-                }
-            }
-        }
-
-        public void publish(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass,
-                Class<?> classSource, Object source, SystemEvent event)
-        {
-            if (source != null && _sourceClassMap != null)
-            {
-                event = _ApplicationUtils._traverseListenerList(facesContext, _sourceClassMap.get(classSource),
-                        systemEventClass, source, event);
-            }
-
-            _ApplicationUtils._traverseListenerList(facesContext, _lstSystemEventListener,
-                    systemEventClass, source, event);
-        }
-
-        private void addListenerNoDuplicate(List<SystemEventListener> listeners, SystemEventListener listener)
-        {
-            if (!listeners.contains(listener))
-            {
-                listeners.add(listener);
-            }
-        }
-
-        private synchronized List<SystemEventListener> getAnySourceListenersNotNull()
-        {
-            if (_lstSystemEventListener == null)
-            {
-                /*
-                 * TODO: Check if modification occurs often or not, might have to use a synchronized list instead.
-                 * 
-                 * Registrations found:
-                 */
-                _lstSystemEventListener = new CopyOnWriteArrayList<>();
-            }
-
-            return _lstSystemEventListener;
-        }
-
-        private synchronized List<SystemEventListener> getSpecificSourceListenersNotNull(Class<?> sourceClass)
-        {
-            if (_sourceClassMap == null)
-            {
-                _sourceClassMap = new ConcurrentHashMap<>();
-            }
-
-            /*
-             * TODO: Check if modification occurs often or not, might have to use a synchronized list instead.
-             * 
-             * Registrations found:
-             */
-            return _sourceClassMap.computeIfAbsent(sourceClass, k -> new CopyOnWriteArrayList<>());
-        }
-    }
-    
     /*
      * private method to look for config objects on a classmap.  The objects can be either a type string
      * or a Class<?> object.  This is done to facilitate lazy loading of config objects.   
diff --git a/impl/src/main/java/org/apache/myfaces/application/ApplicationImplEventManager.java b/impl/src/main/java/org/apache/myfaces/application/ApplicationImplEventManager.java
new file mode 100644
index 0000000..7734fc6
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/application/ApplicationImplEventManager.java
@@ -0,0 +1,363 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.application;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.faces.FacesException;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.SystemEvent;
+import javax.faces.event.SystemEventListener;
+import javax.faces.event.SystemEventListenerHolder;
+
+public class ApplicationImplEventManager
+{
+    private static final Logger log = Logger.getLogger(ApplicationImplEventManager.class.getName());
+    
+    protected static class EventInfo
+    {
+        private Class<? extends SystemEvent> systemEventClass;
+        private Class<?> sourceClass;
+        private SystemEventListener listener;
+    }
+    
+    private ConcurrentHashMap<Class<? extends SystemEvent>, List<EventInfo>> cache
+            = new ConcurrentHashMap<>();
+    private ConcurrentHashMap<Class<? extends SystemEvent>, Constructor<? extends SystemEvent>> constructorCache
+            = new ConcurrentHashMap<>();
+    
+    public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass, Object source)
+    {
+        publishEvent(facesContext, systemEventClass, source.getClass(), source);
+    }
+
+    public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass,
+                             Class<?> sourceBaseType, Object source)
+    {        
+        //Call events only if event processing is enabled.
+        if (!facesContext.isProcessingEvents())
+        {
+            return;
+        }
+        
+        // spec: If this argument is null the return from source.getClass() must be used as the sourceBaseType. 
+        if (sourceBaseType == null)
+        {
+            sourceBaseType = source.getClass();
+        }
+        
+        try
+        {
+            SystemEvent event = null;
+            
+            // component attached listeners
+            if (source instanceof SystemEventListenerHolder)
+            {
+                List<SystemEventListener> listeners =
+                        ((SystemEventListenerHolder) source).getListenersForEventClass(systemEventClass);
+                event = processComponentAttachedListeners(facesContext, listeners, systemEventClass, source, event);
+            }
+
+            
+            // view attached listeners
+            UIViewRoot viewRoot = facesContext.getViewRoot();
+            if (viewRoot != null)
+            {
+                List<SystemEventListener> listeners = viewRoot.getViewListenersForEventClass(systemEventClass);
+                event = processViewAttachedListeners(facesContext, listeners, systemEventClass, source, event);
+            }
+
+            
+            // global listeners
+            List<EventInfo> eventInfos = cache.get(systemEventClass);
+            event = processGlobalListeners(facesContext, eventInfos, systemEventClass, source, event, sourceBaseType);
+        }
+        catch (AbortProcessingException e)
+        {
+            // If the act of invoking the processListener method causes an AbortProcessingException to be thrown,
+            // processing of the listeners must be aborted, no further processing of the listeners for this event must
+            // take place, and the exception must be logged with Level.SEVERE.
+            log.log(Level.SEVERE, "Event processing was aborted", e);
+        }
+    }
+    
+    
+    public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener)
+    {
+        subscribeToEvent(systemEventClass, null, listener);
+    }
+
+    public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass,
+                                 SystemEventListener listener)
+    {
+        List<EventInfo> eventInfos = cache.computeIfAbsent(systemEventClass, k -> new CopyOnWriteArrayList<>());
+        
+        EventInfo eventInfo = new EventInfo();
+        eventInfo.systemEventClass = systemEventClass;
+        eventInfo.sourceClass = sourceClass;
+        eventInfo.listener = listener;
+        
+        eventInfos.add(eventInfo);
+    }
+    
+    public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener)
+    {
+        unsubscribeFromEvent(systemEventClass, null, listener);
+    }
+
+    public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass,
+                                     SystemEventListener listener)
+    {
+        List<EventInfo> eventInfos = cache.get(systemEventClass);
+        if (eventInfos == null || eventInfos.isEmpty())
+        {
+            return;
+        }
+
+        if (sourceClass == null)
+        {
+            eventInfos.removeIf(e -> e.listener.equals(listener));
+        }
+        else
+        {
+            eventInfos.removeIf(e -> e.sourceClass == sourceClass && e.listener.equals(listener));
+        }
+    }
+    
+  
+    
+    
+    protected SystemEvent createEvent(Class<? extends SystemEvent> systemEventClass, FacesContext facesContext,
+            Object source)
+    {
+        Constructor<? extends SystemEvent> constructor = constructorCache.computeIfAbsent(systemEventClass,
+                k -> getConstructor(k));
+        if (constructor == null)
+        {
+            return null;
+        }
+        
+        try
+        {
+            if (constructor.getParameterTypes().length == 2)
+            {
+                return constructor.newInstance(facesContext, source);
+            }
+
+            return constructor.newInstance(source);
+        }
+        catch (Exception e)
+        {
+            throw new FacesException("Couldn't instanciate system event of type " + 
+                    systemEventClass.getName(), e);
+        }
+    }
+    
+    protected Constructor<? extends SystemEvent> getConstructor(Class<? extends SystemEvent> systemEventClass)
+    {
+        Constructor<?>[] constructors = systemEventClass.getConstructors();
+        Constructor<? extends SystemEvent> constructor = null;
+
+        // try to lookup the new 2 parameter constructor
+        for (Constructor<?> c : constructors)
+        {
+            if (c.getParameterTypes().length == 2)
+            {
+                // Safe cast, since the constructor belongs
+                // to a class of type SystemEvent
+                constructor = (Constructor<? extends SystemEvent>) c;
+                break;
+            }
+        }
+
+        // try to lookup the old 1 parameter constructor
+        if (constructor == null)
+        {
+            for (Constructor<?> c : constructors)
+            {
+                if (c.getParameterTypes().length == 1)
+                {
+                    // Safe cast, since the constructor belongs
+                    // to a class of type SystemEvent
+                    constructor = (Constructor<? extends SystemEvent>) c;
+                    break;
+                }
+            }
+        }
+
+        return constructor;
+    }
+    
+
+
+    protected SystemEvent processComponentAttachedListeners(FacesContext facesContext,
+            List<? extends SystemEventListener> listeners, Class<? extends SystemEvent> systemEventClass,
+            Object source, SystemEvent event)
+    {
+        if (listeners == null || listeners.isEmpty())
+        {
+            return event;
+        }
+
+        for (int i  = 0, size = listeners.size(); i < size; i++)
+        {
+            SystemEventListener listener = listeners.get(i);
+            if (listener.isListenerForSource(source))
+            {
+                // Lazy construct the event; zhis same event instance must be passed to all listener instances.
+                if (event == null)
+                {
+                    event = createEvent(systemEventClass, facesContext, source);
+                }
+
+                if (event.isAppropriateListener(listener))
+                {
+                    event.processListener(listener);
+                }
+            }
+        }
+
+        return event;
+    }
+    
+    protected SystemEvent processViewAttachedListeners(FacesContext facesContext,
+            List<? extends SystemEventListener> listeners,
+            Class<? extends SystemEvent> systemEventClass, Object source,
+            SystemEvent event)
+    {
+        if (listeners == null || listeners.isEmpty())
+        {
+            return event;
+        }
+
+        int processedListenerIndex = 0;
+
+        // Do it with a copy because the list could be changed during a event see MYFACES-2935
+        List<SystemEventListener> listenersCopy = new ArrayList<>(listeners);
+
+        // If the inner for is succesful, processedListenerIndex == listenersCopy.size()
+        // and the loop will be complete.
+        while (processedListenerIndex < listenersCopy.size())
+        {                
+            for (; processedListenerIndex < listenersCopy.size(); processedListenerIndex++ )
+            {
+                SystemEventListener listener = listenersCopy.get(processedListenerIndex);
+                if (listener.isListenerForSource(source))
+                {
+                    // Lazy construct the event; zhis same event instance must be passed to all listener instances.
+                    if (event == null)
+                    {
+                        event = createEvent(systemEventClass, facesContext, source);
+                    }
+
+                    if (event.isAppropriateListener(listener))
+                    {
+                        event.processListener(listener);
+                    }
+                }
+            }
+
+            boolean listChanged = false;
+            if (listeners.size() == listenersCopy.size())
+            {
+                for (int i = 0; i < listenersCopy.size(); i++)
+                {
+                    if (listenersCopy.get(i) != listeners.get(i))
+                    {
+                        listChanged = true;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                listChanged = true;
+            }
+
+            if (listChanged)
+            {
+                for (int i = 0; i < listeners.size(); i++)
+                {
+                    SystemEventListener listener = listeners.get(i);
+
+                    // check if listenersCopy.get(i) is valid
+                    if (i < listenersCopy.size())
+                    {
+                        // The normal case is a listener was added, 
+                        // so as heuristic, check first if we can find it at the same location
+                        if (!listener.equals(listenersCopy.get(i)) &&
+                            !listenersCopy.contains(listener))
+                        {
+                            listenersCopy.add(listener);
+                        }
+                    }
+                    else
+                    {
+                        if (!listenersCopy.contains(listener))
+                        {
+                            listenersCopy.add(listener);
+                        }
+                    }
+                }
+            }
+        }
+
+        return event;
+    }
+    
+    protected SystemEvent processGlobalListeners(FacesContext facesContext, List<EventInfo> eventInfos,
+            Class<? extends SystemEvent> systemEventClass, Object source, SystemEvent event, Class<?> sourceBaseType)
+    {
+        if (eventInfos == null || eventInfos.isEmpty())
+        {
+            return event;
+        }
+        
+        for (int i  = 0, size = eventInfos.size(); i < size; i++)
+        {
+            EventInfo eventInfo = eventInfos.get(i);
+            if (eventInfo.sourceClass != null && !eventInfo.sourceClass.isAssignableFrom(sourceBaseType))
+            {
+                continue;
+            }
+
+            if (eventInfo.listener.isListenerForSource(source))
+            {
+                if (event == null)
+                {
+                    event = createEvent(systemEventClass, facesContext, source);
+                }
+
+                if (event.isAppropriateListener(eventInfo.listener))
+                {
+                    event.processListener(eventInfo.listener);
+                }
+            }
+        }
+        
+        return event;
+    }
+}
diff --git a/impl/src/main/java/org/apache/myfaces/application/_ApplicationUtils.java b/impl/src/main/java/org/apache/myfaces/application/_ApplicationUtils.java
deleted file mode 100644
index f16ee07..0000000
--- a/impl/src/main/java/org/apache/myfaces/application/_ApplicationUtils.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.application;
-
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.List;
-import javax.faces.FacesException;
-import javax.faces.context.FacesContext;
-import javax.faces.event.SystemEvent;
-import javax.faces.event.SystemEventListener;
-
-/**
- *
- * lu4242
- */
-class _ApplicationUtils
-{
-    // TODO we could cache the constructor, it's called very often.
-    static SystemEvent _createEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass,
-            Object source, SystemEvent event)
-    {
-        if (event == null)
-        {
-            try
-            {
-                Constructor<?>[] constructors = systemEventClass.getConstructors();
-                Constructor<? extends SystemEvent> constructor = null;
-             
-                // try to lookup the new 2 parameter constructor
-                for (Constructor<?> c : constructors)
-                {
-                    if (c.getParameterTypes().length == 2)
-                    {
-                        // Safe cast, since the constructor belongs
-                        // to a class of type SystemEvent
-                        constructor = (Constructor<? extends SystemEvent>) c;
-                        break;
-                    }
-                }
-                if (constructor != null)
-                {
-                    event = constructor.newInstance(facesContext, source);
-                }
-                
-                // try to lookup the old 1 parameter constructor
-                if (constructor == null)
-                {
-                    for (Constructor<?> c : constructors)
-                    {
-                        if (c.getParameterTypes().length == 1)
-                        {
-                            // Safe cast, since the constructor belongs
-                            // to a class of type SystemEvent
-                            constructor = (Constructor<? extends SystemEvent>) c;
-                            break;
-                        }
-                    }
-                    if (constructor != null)
-                    {
-                        event = constructor.newInstance(source);
-                    }
-                }
-            }
-            catch (Exception e)
-            {
-                throw new FacesException("Couldn't instanciate system event of type " + 
-                        systemEventClass.getName(), e);
-            }
-        }
-
-        return event;
-    }
-
-    static SystemEvent _traverseListenerList(FacesContext facesContext, List<? extends SystemEventListener> listeners,
-                                                     Class<? extends SystemEvent> systemEventClass, Object source,
-                                                     SystemEvent event)
-    {
-        if (listeners != null && !listeners.isEmpty())
-        {
-            // perf: org.apache.myfaces.application.ApplicationImpl.
-            //    SystemListenerEntry.getSpecificSourceListenersNotNull(Class<?>)
-            // or javax.faces.component.UIComponent.subscribeToEvent(
-            //      Class<? extends SystemEvent>, ComponentSystemEventListener)
-            // creates a ArrayList:
-            for (int i  = 0, size = listeners.size(); i < size; i++)
-            {
-                SystemEventListener listener = listeners.get(i);
-                // Call SystemEventListener.isListenerForSource(java.lang.Object), passing the source argument.
-                // If this returns false, take no action on the listener.
-                if (listener.isListenerForSource(source))
-                {
-                    // Otherwise, if the event to be passed to the listener instances has not yet been constructed,
-                    // construct the event, passing source as the argument to the one-argument constructor that takes
-                    // an Object. This same event instance must be passed to all listener instances.
-                    event = _createEvent(facesContext, systemEventClass, source, event);
-
-                    // Call SystemEvent.isAppropriateListener(javax.faces.event.FacesListener), passing the listener
-                    // instance as the argument. If this returns false, take no action on the listener.
-                    if (event.isAppropriateListener(listener))
-                    {
-                        // Call SystemEvent.processListener(javax.faces.event.FacesListener), passing the listener
-                        // instance.
-                        event.processListener(listener);
-                    }
-                }
-            }
-        }
-
-        return event;
-    }
-    
-    // Do it with a copy because the list could be changed during a event
-    // see MYFACES-2935
-    static SystemEvent _traverseListenerListWithCopy(FacesContext facesContext,
-            List<? extends SystemEventListener> listeners,
-            Class<? extends SystemEvent> systemEventClass, Object source,
-            SystemEvent event)
-    {
-        if (listeners != null && !listeners.isEmpty())
-        {
-            int processedListenerIndex = 0;
-
-            List<SystemEventListener> listenersCopy = new ArrayList<SystemEventListener>(listeners);
-            
-            // If the inner for is succesful, processedListenerIndex == listenersCopy.size()
-            // and the loop will be complete.
-            while (processedListenerIndex < listenersCopy.size())
-            {                
-                for (; processedListenerIndex < listenersCopy.size(); processedListenerIndex++ )
-                {
-                    SystemEventListener listener = listenersCopy.get(processedListenerIndex);
-                    // Call SystemEventListener.isListenerForSource(java.lang.Object), passing the source argument.
-                    // If this returns false, take no action on the listener.
-                    if (listener.isListenerForSource(source))
-                    {
-                        // Otherwise, if the event to be passed to the listener instances has not yet been constructed,
-                        // construct the event, passing source as the argument
-                        // to the one-argument constructor that takes
-                        // an Object. This same event instance must be passed to all listener instances.
-                        event = _createEvent(facesContext, systemEventClass, source, event);
-    
-                        // Call SystemEvent.isAppropriateListener(javax.faces.event.FacesListener), passing the listener
-                        // instance as the argument. If this returns false, take no action on the listener.
-                        if (event.isAppropriateListener(listener))
-                        {
-                            // Call SystemEvent.processListener(javax.faces.event.FacesListener), passing the listener
-                            // instance.
-                            event.processListener(listener);
-                        }
-                    }
-                }
-                
-                boolean listChanged = false;
-                if (listeners.size() == listenersCopy.size())
-                {
-                    for (int i = 0; i < listenersCopy.size(); i++)
-                    {
-                        if (listenersCopy.get(i) != listeners.get(i))
-                        {
-                            listChanged = true;
-                            break;
-                        }
-                    }
-                }
-                else
-                {
-                    listChanged = true;
-                }
-                
-                if (listChanged)
-                {
-                    for (int i = 0; i < listeners.size(); i++)
-                    {
-                        SystemEventListener listener = listeners.get(i);
-                        
-                        // check if listenersCopy.get(i) is valid
-                        if (i < listenersCopy.size())
-                        {
-                            // The normal case is a listener was added, 
-                            // so as heuristic, check first
-                            // if we can find it at the same location
-                            if (!listener.equals(listenersCopy.get(i)) &&
-                                !listenersCopy.contains(listener))
-                            {
-                                listenersCopy.add(listener);
-                            }
-                        }
-                        else
-                        {
-                            if (!listenersCopy.contains(listener))
-                            {
-                                listenersCopy.add(listener);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        return event;
-    }
-
-
-}
diff --git a/impl/src/test/java/org/apache/myfaces/application/ApplicationImplTest.java b/impl/src/test/java/org/apache/myfaces/application/ApplicationImplTest.java
index 29fe03a..8af55af 100644
--- a/impl/src/test/java/org/apache/myfaces/application/ApplicationImplTest.java
+++ b/impl/src/test/java/org/apache/myfaces/application/ApplicationImplTest.java
@@ -56,13 +56,13 @@ public class ApplicationImplTest extends TestCase
     //TODO: need mock objects for VDL/VDLFactory
     //remove from excludes list in pom.xml after complete
     
-    private ApplicationImpl app;
-    private MockFacesContext context;
+    protected ApplicationImpl application;
+    protected MockFacesContext facesContext;
 
     protected void setUp() throws Exception
     {
-        app = new ApplicationImpl(new RuntimeConfig());
-        context = new MockFacesContext();
+        application = new ApplicationImpl(new RuntimeConfig());
+        facesContext = new MockFacesContext();
     }
 
     /**
@@ -75,14 +75,14 @@ public class ApplicationImplTest extends TestCase
         {
             public void run()
             {
-                app.getResourceBundle(null, "xxx");
+                application.getResourceBundle(null, "xxx");
             }
         });
         MyFacesAsserts.assertException(NullPointerException.class, new TestRunner()
         {
             public void run()
             {
-                app.getResourceBundle(context, null);
+                application.getResourceBundle(facesContext, null);
             }
         });
     }
@@ -108,7 +108,7 @@ public class ApplicationImplTest extends TestCase
         {
             public void run()
             {
-                myApp.getResourceBundle(context, "xxx");
+                myApp.getResourceBundle(facesContext, "xxx");
             }
         });
     }
@@ -130,7 +130,7 @@ public class ApplicationImplTest extends TestCase
     {
         Locale locale = new Locale("xx");
         UIViewRoot viewRoot = new UIViewRoot();
-        context.setViewRoot(viewRoot);
+        facesContext.setViewRoot(viewRoot);
         viewRoot.setLocale(locale);
         assertGetResourceBundleWithLocale(locale);
     }
@@ -143,10 +143,10 @@ public class ApplicationImplTest extends TestCase
         expect(context.getELContext()).andReturn(elcontext);
         expect(expr.getValue(elcontext)).andReturn(null);
         expr.setValue(eq(elcontext), isA(UIOutput.class));
-        app.addComponent("testComponent", UIOutput.class.getName());
+        application.addComponent("testComponent", UIOutput.class.getName());
         replay(context);
         replay(expr);
-        assertTrue(UIOutput.class.isAssignableFrom(app.createComponent(expr, context, "testComponent").getClass()));
+        assertTrue(UIOutput.class.isAssignableFrom(application.createComponent(expr, context, "testComponent").getClass()));
     }
 
     public void testCreateComponentExpressionFacesExceptionTest() throws Exception
@@ -160,7 +160,7 @@ public class ApplicationImplTest extends TestCase
         replay(expr);
         try
         {
-            app.createComponent(expr, context, "testComponent");
+            application.createComponent(expr, context, "testComponent");
         }
         catch (FacesException e)
         {
@@ -202,7 +202,7 @@ public class ApplicationImplTest extends TestCase
                 return bundle;
             }
         };
-        assertSame(bundle, myapp.getResourceBundle(context, var));
+        assertSame(bundle, myapp.getResourceBundle(facesContext, var));
     }
 
     private enum MyEnum {VALUE1, VALUE2}; 
@@ -213,9 +213,9 @@ public class ApplicationImplTest extends TestCase
      */
     public void testCreateEnumConverter() throws Exception
     {
-        app.addConverter(Enum.class, EnumConverter.class.getName());
+        application.addConverter(Enum.class, EnumConverter.class.getName());
 
-        Converter converter = app.createConverter(MyEnum.class);
+        Converter converter = application.createConverter(MyEnum.class);
         assertNotNull(converter);
         assertEquals(converter.getClass(), EnumConverter.class);
     }    
@@ -258,10 +258,10 @@ public class ApplicationImplTest extends TestCase
      */
     public void testCreateConverterForInterface() throws Exception 
     {
-        app.addConverter(Enum.class, EnumConverter.class.getName());
-    	app.addConverter(EnumCoded.class, EnumCodedTestConverter.class.getName());
+        application.addConverter(Enum.class, EnumConverter.class.getName());
+    	application.addConverter(EnumCoded.class, EnumCodedTestConverter.class.getName());
     	
-    	Converter converter = app.createConverter(AnotherEnum.class);
+    	Converter converter = application.createConverter(AnotherEnum.class);
     	assertNotNull(converter);
         assertEquals(converter.getClass(), EnumCodedTestConverter.class);
     }
diff --git a/impl/src/test/java/org/apache/myfaces/event/GlobalPostAddToViewEventTestCase.java b/impl/src/test/java/org/apache/myfaces/event/GlobalPostAddToViewEventTestCase.java
index 4568290..aef65d0 100644
--- a/impl/src/test/java/org/apache/myfaces/event/GlobalPostAddToViewEventTestCase.java
+++ b/impl/src/test/java/org/apache/myfaces/event/GlobalPostAddToViewEventTestCase.java
@@ -19,10 +19,13 @@
 package org.apache.myfaces.event;
 
 import javax.faces.component.UIComponent;
+import javax.faces.component.UIOutput;
 import javax.faces.component.html.HtmlHead;
+import javax.faces.component.html.HtmlInputText;
 import javax.faces.event.PostAddToViewEvent;
 import javax.faces.event.SystemEvent;
 import javax.faces.event.SystemEventListener;
+import org.apache.myfaces.application.ApplicationImplEventManager;
 import org.apache.myfaces.test.base.junit4.AbstractJsfConfigurableMockTestCase;
 
 import org.junit.Assert;
@@ -46,20 +49,50 @@ public class GlobalPostAddToViewEventTestCase extends AbstractJsfConfigurableMoc
     }
 
     @Test
-    public void testPostAddToViewForHead() throws Exception
+    public void postAddToViewSourceNull() throws Exception
     {
-        application.subscribeToEvent(PostAddToViewEvent.class, new HeadResourceListener());
+        ApplicationImplEventManager eventManager = new ApplicationImplEventManager();
+        
+        eventManager.subscribeToEvent(PostAddToViewEvent.class, new HeadResourceListener());
+
+        eventManager.publishEvent(facesContext, PostAddToViewEvent.class, HtmlHead.class, new HtmlHead());
 
-        application.addComponent(HtmlHead.COMPONENT_TYPE,
-                HtmlHead.class.getName());
+        Assert.assertTrue(facesContext.getAttributes().containsKey("SystemEventListenerInvokedForHead"));
+    }
+    
+    @Test
+    public void postAddToViewSourceSuperClass() throws Exception
+    {
+        ApplicationImplEventManager eventManager = new ApplicationImplEventManager();
         
-        HtmlHead comp = (HtmlHead) application.createComponent(facesContext, 
-                HtmlHead.COMPONENT_TYPE,
-                "javax.faces.Head");
+        eventManager.subscribeToEvent(PostAddToViewEvent.class, UIOutput.class, new HeadResourceListener());
+
+        eventManager.publishEvent(facesContext, PostAddToViewEvent.class, HtmlHead.class, new HtmlHead());
+
+        Assert.assertTrue(facesContext.getAttributes().containsKey("SystemEventListenerInvokedForHead"));
+    }
+    
+    @Test
+    public void postAddToViewSourceDirect() throws Exception
+    {
+        ApplicationImplEventManager eventManager = new ApplicationImplEventManager();
         
-        // Invoke PostAddToViewEvent
-        facesContext.getViewRoot().getChildren().add(comp);
+        eventManager.subscribeToEvent(PostAddToViewEvent.class, HtmlHead.class, new HeadResourceListener());
+
+        eventManager.publishEvent(facesContext, PostAddToViewEvent.class, HtmlHead.class, new HtmlHead());
 
         Assert.assertTrue(facesContext.getAttributes().containsKey("SystemEventListenerInvokedForHead"));
     }
+    
+    @Test
+    public void postAddToViewSourceUnmatching() throws Exception
+    {
+        ApplicationImplEventManager eventManager = new ApplicationImplEventManager();
+        
+        eventManager.subscribeToEvent(PostAddToViewEvent.class, HtmlInputText.class, new HeadResourceListener());
+
+        eventManager.publishEvent(facesContext, PostAddToViewEvent.class, HtmlHead.class, new HtmlHead());
+
+        Assert.assertFalse(facesContext.getAttributes().containsKey("SystemEventListenerInvokedForHead"));
+    }
 }