FELIX-3321 : Improve implementation and reduce load on the service registry

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1236655 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java
index 858b092..ee95279 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java
@@ -22,10 +22,9 @@
 import java.util.*;
 
 import org.apache.felix.eventadmin.impl.adapter.*;
-import org.apache.felix.eventadmin.impl.dispatch.DefaultThreadPool;
-import org.apache.felix.eventadmin.impl.handler.*;
+import org.apache.felix.eventadmin.impl.handler.EventAdminImpl;
 import org.apache.felix.eventadmin.impl.security.SecureEventAdminFactory;
-import org.apache.felix.eventadmin.impl.util.LeastRecentlyUsedCacheMap;
+import org.apache.felix.eventadmin.impl.tasks.DefaultThreadPool;
 import org.apache.felix.eventadmin.impl.util.LogWrapper;
 import org.osgi.framework.*;
 import org.osgi.service.cm.ConfigurationException;
@@ -41,14 +40,6 @@
  * The service knows about the following properties which are read at bundle startup:
  * <p>
  * <p>
- *      <tt>org.apache.felix.eventadmin.CacheSize</tt> - The size of various internal
- *          caches.
- * </p>
- * The default value is 30. Increase in case of a large number (more then 100) of
- * <tt>EventHandler</tt> services. A value less then 10 triggers the default value.
- * </p>
- * <p>
- * <p>
  *      <tt>org.apache.felix.eventadmin.ThreadPoolSize</tt> - The size of the thread
  *          pool.
  * </p>
@@ -96,13 +87,14 @@
  * These properties are read at startup and serve as a default configuration.
  * If a configuration admin is configured, the event admin can be configured
  * through the config admin.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class Configuration
 {
     /** The PID for the event admin. */
     static final String PID = "org.apache.felix.eventadmin.impl.EventAdmin";
 
-    static final String PROP_CACHE_SIZE = "org.apache.felix.eventadmin.CacheSize";
     static final String PROP_THREAD_POOL_SIZE = "org.apache.felix.eventadmin.ThreadPoolSize";
     static final String PROP_TIMEOUT = "org.apache.felix.eventadmin.Timeout";
     static final String PROP_REQUIRE_TOPIC = "org.apache.felix.eventadmin.RequireTopic";
@@ -112,8 +104,6 @@
     /** The bundle context. */
     private final BundleContext m_bundleContext;
 
-    private int m_cacheSize;
-
     private int m_threadPoolSize;
 
     private int m_timeout;
@@ -207,14 +197,6 @@
     {
         if ( config == null )
         {
-            // The size of various internal caches. At the moment there are 4
-            // internal caches affected. Each will cache the determined amount of
-            // small but frequently used objects (i.e., in case of the default value
-            // we end-up with a total of 120 small objects being cached). A value of less
-            // then 10 triggers the default value.
-            m_cacheSize = getIntProperty(PROP_CACHE_SIZE,
-                m_bundleContext.getProperty(PROP_CACHE_SIZE), 30, 10);
-
             // The size of the internal thread pool. Note that we must execute
             // each synchronous event dispatch that happens in the synchronous event
             // dispatching thread in a new thread, hence a small thread pool is o.k.
@@ -260,7 +242,6 @@
         }
         else
         {
-            m_cacheSize = getIntProperty(PROP_CACHE_SIZE, config.get(PROP_CACHE_SIZE), 30, 10);
             m_threadPoolSize = getIntProperty(PROP_THREAD_POOL_SIZE, config.get(PROP_THREAD_POOL_SIZE), 20, 2);
             m_timeout = getIntProperty(PROP_TIMEOUT, config.get(PROP_TIMEOUT), 5000, Integer.MIN_VALUE);
             m_requireTopic = getBooleanProperty(config.get(PROP_REQUIRE_TOPIC), true);
@@ -297,21 +278,12 @@
         LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
                 PROP_LOG_LEVEL + "=" + m_logLevel);
         LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
-                PROP_CACHE_SIZE + "=" + m_cacheSize);
-        LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
             PROP_THREAD_POOL_SIZE + "=" + m_threadPoolSize);
         LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
             PROP_TIMEOUT + "=" + m_timeout);
         LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
             PROP_REQUIRE_TOPIC + "=" + m_requireTopic);
 
-        final TopicHandlerFilters topicHandlerFilters =
-            new CacheTopicHandlerFilters(new LeastRecentlyUsedCacheMap(m_cacheSize),
-            m_requireTopic);
-
-        final Filters filters = new CacheFilters(
-            new LeastRecentlyUsedCacheMap(m_cacheSize), m_bundleContext);
-
         // Note that this uses a lazy thread pool that will create new threads on
         // demand - in case none of its cached threads is free - until threadPoolSize
         // is reached. Subsequently, a threadPoolSize of 2 effectively disables
@@ -334,16 +306,14 @@
             m_async_pool.configure(asyncThreadPoolSize);
         }
 
-        // The handlerTasks object is responsible to determine concerned EventHandler
-        // for a given event. Additionally, it keeps a list of blacklisted handlers.
-        // Note that blacklisting is deactivated by selecting a different scheduler
-        // below (and not in this HandlerTasks object!)
-        final HandlerTasks handlerTasks = new BlacklistingHandlerTasks(m_bundleContext,
-            new CleanBlackList(), topicHandlerFilters, filters);
-
         if ( m_admin == null )
         {
-            m_admin = new EventAdminImpl(handlerTasks, m_sync_pool, m_async_pool, m_timeout, m_ignoreTimeout);
+            m_admin = new EventAdminImpl(m_bundleContext,
+                    m_sync_pool,
+                    m_async_pool,
+                    m_timeout,
+                    m_ignoreTimeout,
+                    m_requireTopic);
 
             // Finally, adapt the outside events to our kind of events as per spec
             adaptEvents(m_admin);
@@ -356,7 +326,7 @@
         }
         else
         {
-            m_admin.update(handlerTasks, m_timeout, m_ignoreTimeout);
+            m_admin.update(m_timeout, m_ignoreTimeout, m_requireTopic);
         }
 
     }
@@ -426,10 +396,10 @@
         try
         {
             return new MetaTypeProviderImpl((ManagedService)managedService,
-                    m_cacheSize, m_threadPoolSize, m_timeout, m_requireTopic,
+                    m_threadPoolSize, m_timeout, m_requireTopic,
                     m_ignoreTimeout);
         }
-        catch (Throwable t)
+        catch (final Throwable t)
         {
             // we simply ignore this
         }
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/EventAdminImpl.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/EventAdminImpl.java
deleted file mode 100644
index 9c868b1..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/EventAdminImpl.java
+++ /dev/null
@@ -1,181 +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.felix.eventadmin.impl;
-
-import java.util.List;
-
-import org.apache.felix.eventadmin.impl.dispatch.DefaultThreadPool;
-import org.apache.felix.eventadmin.impl.handler.HandlerTasks;
-import org.apache.felix.eventadmin.impl.tasks.*;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventAdmin;
-
-/**
- * This is the actual implementation of the OSGi R4 Event Admin Service (see the
- * Compendium 113 for details). The implementation uses a <tt>HandlerTasks</tt>
- * in order to determine applicable <tt>EventHandler</tt> for a specific event and
- * subsequently dispatches the event to the handlers via <tt>DeliverTasks</tt>.
- * To do this, it uses two different <tt>DeliverTasks</tt> one for asynchronous and
- * one for synchronous event delivery depending on whether its <tt>post()</tt> or
- * its <tt>send()</tt> method is called. Note that the actual work is done in the
- * implementations of the <tt>DeliverTasks</tt>. Additionally, a stop method is
- * provided that prevents subsequent events to be delivered.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public class EventAdminImpl implements EventAdmin
-{
-    // The factory used to determine applicable EventHandlers - this will be replaced
-    // by a null object in stop() that subsequently throws an IllegalStateException
-    private volatile HandlerTasks m_managers;
-
-    // The asynchronous event dispatcher
-    private final DeliverTask m_postManager;
-
-    // The synchronous event dispatcher
-    private final SyncDeliverTasks m_sendManager;
-
-    /**
-     * The constructor of the <tt>EventAdmin</tt> implementation. The
-     * <tt>HandlerTasks</tt> factory is used to determine applicable
-     * <tt>EventHandler</tt> for a given event. Additionally, the two
-     * <tt>DeliverTasks</tt> are used to dispatch the event.
-     *
-     * @param managers The factory used to determine applicable <tt>EventHandler</tt>
-     * @param syncPool The synchronous thread pool
-     * @param asyncPool The asynchronous thread pool
-     */
-    public EventAdminImpl(final HandlerTasks managers,
-            final DefaultThreadPool syncPool,
-            final DefaultThreadPool asyncPool,
-            final int timeout,
-            final String[] ignoreTimeout)
-    {
-        checkNull(managers, "Managers");
-        checkNull(syncPool, "syncPool");
-        checkNull(asyncPool, "asyncPool");
-
-        m_managers = managers;
-
-        m_sendManager = new SyncDeliverTasks(syncPool,
-                (timeout > 100 ? timeout : 0),
-                ignoreTimeout);
-
-        m_postManager = new AsyncDeliverTasks(asyncPool, m_sendManager);
-    }
-
-    /**
-     * Post an asynchronous event.
-     *
-     * @param event The event to be posted by this service
-     *
-     * @throws IllegalStateException - In case we are stopped
-     *
-     * @see org.osgi.service.event.EventAdmin#postEvent(org.osgi.service.event.Event)
-     */
-    public void postEvent(final Event event)
-    {
-        handleEvent(m_managers.createHandlerTasks(event), m_postManager);
-    }
-
-    /**
-     * Send a synchronous event.
-     *
-     * @param event The event to be send by this service
-     *
-     * @throws IllegalStateException - In case we are stopped
-     *
-     * @see org.osgi.service.event.EventAdmin#sendEvent(org.osgi.service.event.Event)
-     */
-    public void sendEvent(final Event event)
-    {
-        handleEvent(m_managers.createHandlerTasks(event), m_sendManager);
-    }
-
-    /**
-     * This method can be used to stop the delivery of events. The m_managers is
-     * replaced with a null object that throws an IllegalStateException on a call
-     * to <tt>createHandlerTasks()</tt>.
-     */
-    public void stop()
-    {
-        // replace the HandlerTasks with a null object that will throw an
-        // IllegalStateException on a call to createHandlerTasks
-        m_managers = new HandlerTasks()
-        {
-            /**
-             * This is a null object and this method will throw an
-             * IllegalStateException due to the bundle being stopped.
-             *
-             * @param event An event that is not used.
-             *
-             * @return This method does not return normally
-             *
-             * @throws IllegalStateException - This is a null object and this method
-             *          will always throw an IllegalStateException
-             */
-            public List createHandlerTasks(final Event event)
-            {
-                throw new IllegalStateException("The EventAdmin is stopped");
-            }
-        };
-    }
-
-    /**
-     * Update the event admin with new configuration.
-     */
-    public void update(final HandlerTasks managers, final int timeout,
-            final String[] ignoreTimeout)
-    {
-        m_managers = managers;
-        m_sendManager.update(timeout, ignoreTimeout);
-    }
-
-    /**
-     * This is a utility method that uses the given DeliverTasks to create a
-     * dispatch tasks that subsequently is used to dispatch the given HandlerTasks.
-     */
-    private void handleEvent(List managers,
-        final DeliverTask manager)
-    {
-        if (managers != null && managers.size() > 0 )
-        {
-            // This might throw an IllegalStateException in case that we are stopped
-            // and the null object for m_managers was not fast enough established
-            // This is needed in the adapter/* classes due to them sending
-            // events whenever they receive an event from their source.
-            // Service importers that call us regardless of the fact that we are
-            // stopped deserve an exception anyways
-            manager.execute(managers);
-        }
-    }
-
-    /**
-     * This is a utility method that will throw a <tt>NullPointerException</tt>
-     * in case that the given object is null. The message will be of the form
-     * "${name} + may not be null".
-     */
-    private void checkNull(final Object object, final String name)
-    {
-        if(null == object)
-        {
-            throw new NullPointerException(name + " may not be null");
-        }
-    }
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/MetaTypeProviderImpl.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/MetaTypeProviderImpl.java
index 0ccc102..c5dbf72 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/MetaTypeProviderImpl.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/MetaTypeProviderImpl.java
@@ -28,11 +28,12 @@
 
 /**
  * The optional meta type provider for the event admin config.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class MetaTypeProviderImpl
     implements MetaTypeProvider, ManagedService
 {
-    private final int m_cacheSize;
     private final int m_threadPoolSize;
     private final int m_timeout;
     private final boolean m_requireTopic;
@@ -41,11 +42,10 @@
     private final ManagedService m_delegatee;
 
     public MetaTypeProviderImpl(final ManagedService delegatee,
-            final int cacheSize, final int threadPoolSize,
+            final int threadPoolSize,
             final int timeout, final boolean requireTopic,
             final String[] ignoreTimeout)
     {
-        m_cacheSize = cacheSize;
         m_threadPoolSize = threadPoolSize;
         m_timeout = timeout;
         m_requireTopic = requireTopic;
@@ -85,11 +85,6 @@
         {
             final ArrayList adList = new ArrayList();
 
-            adList.add( new AttributeDefinitionImpl( Configuration.PROP_CACHE_SIZE, "Cache Size",
-                    "The size of various internal caches. The default value is 30. Increase in case " +
-                    "of a large number (more then 100) of services. A value less then 10 triggers the " +
-                    "default value.", m_cacheSize) );
-
             adList.add( new AttributeDefinitionImpl( Configuration.PROP_THREAD_POOL_SIZE, "Thread Pool Size",
                 "The size of the thread pool. The default value is 10. Increase in case of a large amount " +
                 "of synchronous events where the event handler services in turn send new synchronous events in " +
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java
index 8e5cde2..8a687d4 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java
@@ -24,6 +24,7 @@
 /**
  * Abstract base class for all adapters.
  * This class allows to exchange the event admin at runtime
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public abstract class AbstractAdapter
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/BlackList.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/BlackList.java
deleted file mode 100644
index c409487..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/BlackList.java
+++ /dev/null
@@ -1,49 +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.felix.eventadmin.impl.handler;
-
-import org.osgi.framework.ServiceReference;
-
-/**
- * This interface represents a simple set that allows to add service references
- * and lookup whether a given reference is in the list. Note that implementations
- * of this interface may do additional service reference life-cycle related
- * clean-up actions like removing references that point to unregistered services.
- * 
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public interface BlackList
-{
-    /**
-     * Add a service to this blacklist.
-     * 
-     * @param ref The reference of the service that is blacklisted
-     */
-    public void add(final ServiceReference ref);
-    
-    /**
-     * Lookup whether a given service is blacklisted.
-     * 
-     * @param ref The reference of the service
-     * 
-     * @return <tt>true</tt> in case that the service reference has been blacklisted, 
-     *      <tt>false</tt> otherwise.
-     */
-    public boolean contains(final ServiceReference ref);
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/BlacklistingHandlerTasks.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/BlacklistingHandlerTasks.java
deleted file mode 100644
index 84282ed..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/BlacklistingHandlerTasks.java
+++ /dev/null
@@ -1,238 +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.felix.eventadmin.impl.handler;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.felix.eventadmin.impl.security.PermissionsUtil;
-import org.apache.felix.eventadmin.impl.tasks.HandlerTaskImpl;
-import org.apache.felix.eventadmin.impl.util.LogWrapper;
-import org.osgi.framework.*;
-import org.osgi.service.event.*;
-
-/**
- * This class is an implementation of the HandlerTasks interface that does provide
- * blacklisting of event handlers. Furthermore, handlers are determined from the
- * framework on any call to <tt>createHandlerTasks()</tt> hence, there is no
- * book-keeping of <tt>EventHandler</tt> services while they come and go but a
- * query for each sent event. In order to do this, an ldap-filter is created that
- * will match applicable <tt>EventHandler</tt> references. In order to ease some of
- * the overhead pains of this approach some light caching is going on.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public class BlacklistingHandlerTasks implements HandlerTasks
-{
-    // The blacklist that holds blacklisted event handler service references
-    private final BlackList m_blackList;
-
-    // The context of the bundle used to get the actual event handler services
-    private final BundleContext m_context;
-
-    // Used to create the filters that can determine applicable event handlers for
-    // a given event
-    private final TopicHandlerFilters m_topicHandlerFilters;
-
-    // Used to create the filters that are used to determine whether an applicable
-    // event handler is interested in a particular event
-    private final Filters m_filters;
-
-    /**
-     * The constructor of the factory.
-     *
-     * @param context The context of the bundle
-     * @param blackList The set to use for keeping track of blacklisted references
-     * @param topicHandlerFilters The factory for topic handler filters
-     * @param filters The factory for <tt>Filter</tt> objects
-     */
-    public BlacklistingHandlerTasks(final BundleContext context,
-        final BlackList blackList,
-        final TopicHandlerFilters topicHandlerFilters, final Filters filters)
-    {
-        checkNull(context, "Context");
-        checkNull(blackList, "BlackList");
-        checkNull(topicHandlerFilters, "TopicHandlerFilters");
-        checkNull(filters, "Filters");
-
-        m_context = context;
-
-        m_blackList = blackList;
-
-        m_topicHandlerFilters = topicHandlerFilters;
-
-        m_filters = filters;
-    }
-
-    /**
-     * Create the handler tasks for the event. All matching event handlers are
-     * determined and delivery tasks for them returned.
-     *
-     * @param event The event for which' handlers delivery tasks must be created
-     *
-     * @return A delivery task for each handler that matches the given event
-     *
-     * @see org.apache.felix.eventadmin.impl.handler.HandlerTasks#createHandlerTasks(org.osgi.service.event.Event)
-     */
-    public List createHandlerTasks(final Event event)
-    {
-        ServiceReference[] handlerRefs = null;
-
-        try
-        {
-            handlerRefs = m_context.getServiceReferences(EventHandler.class
-                .getName(), m_topicHandlerFilters.createFilterForTopic(event
-                .getTopic()));
-        } catch (InvalidSyntaxException e)
-        {
-            LogWrapper.getLogger().log(LogWrapper.LOG_WARNING,
-                "Invalid EVENT_TOPIC [" + event.getTopic() + "]", e);
-        }
-
-        if (null == handlerRefs || handlerRefs.length == 0 )
-        {
-            return null;
-        }
-
-        final List result = new ArrayList();
-        for (int i = 0; i < handlerRefs.length; i++)
-        {
-            final ServiceReference ref = handlerRefs[i];
-            final Bundle serviceBundle = ref.getBundle();
-            if ( serviceBundle != null )
-            {
-                if (!m_blackList.contains(ref)
-                    && serviceBundle.hasPermission(
-                          PermissionsUtil.createSubscribePermission(event.getTopic())))
-                {
-                    try
-                    {
-                        if (event.matches(m_filters.createFilter(
-                            (String) ref.getProperty(EventConstants.EVENT_FILTER))))
-                        {
-                            result.add(new HandlerTaskImpl(ref, event, this));
-                        }
-                    } catch (InvalidSyntaxException e)
-                    {
-                        LogWrapper.getLogger().log(
-                            ref,
-                            LogWrapper.LOG_WARNING,
-                            "Invalid EVENT_FILTER - Blacklisting ServiceReference ["
-                                + ref + " | Bundle("
-                                + serviceBundle + ")]", e);
-
-                        m_blackList.add(ref);
-                    }
-                }
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * Blacklist the given service reference. This is a private method and only
-     * public due to its usage in a friend class.
-     *
-     * @param handlerRef The service reference to blacklist
-     */
-    public void blackList(final ServiceReference handlerRef)
-    {
-        m_blackList.add(handlerRef);
-
-        LogWrapper.getLogger().log(
-            LogWrapper.LOG_WARNING,
-            "Blacklisting ServiceReference [" + handlerRef + " | Bundle("
-                + handlerRef.getBundle() + ")] due to timeout!");
-    }
-
-    /**
-     * Get the real EventHandler service for the handlerRef from the context in case
-     * the ref is not blacklisted and the service is not unregistered. The
-     * NullEventHandler object is returned otherwise. This is a private method and
-     * only public due to its usage in a friend class.
-     *
-     * @param handlerRef The service reference for which to get its service
-     * @return The service of the reference or a null object if the service is
-     *      unregistered
-     */
-    public EventHandler getEventHandler(final ServiceReference handlerRef)
-    {
-        final Object result = (m_blackList.contains(handlerRef)) ? null
-            : m_context.getService(handlerRef);
-
-        return (EventHandler) ((null != result) ? result : m_nullEventHandler);
-    }
-
-    /**
-     * Unget the service reference for the given event handler unless it is the
-     * NullEventHandler. This is a private method and only public due to
-     * its usage in a friend class.
-     *
-     * @param handler The event handler service to unget
-     * @param handlerRef The service reference to unget
-     */
-    public void ungetEventHandler(final EventHandler handler,
-            final ServiceReference handlerRef)
-    {
-            if(m_nullEventHandler != handler)
-            {
-                // Is the handler not unregistered or blacklisted?
-                if(!m_blackList.contains(handlerRef) && (null !=
-                    handlerRef.getBundle()))
-                {
-                    m_context.ungetService(handlerRef);
-                }
-            }
-    }
-
-    /*
-     * This is a null object that is supposed to do nothing. This is used once an
-     * EventHandler is requested for a service reference that is either stale
-     * (i.e., unregistered) or blacklisted
-     */
-    private final EventHandler m_nullEventHandler = new EventHandler()
-    {
-        /**
-         * This is a null object that is supposed to do nothing at this point.
-         *
-         * @param event an event that is not used
-         */
-        public void handleEvent(final Event event)
-        {
-            // This is a null object that is supposed to do nothing at this
-            // point. This is used once a EventHandler is requested for a
-            // servicereference that is either stale (i.e., unregistered) or
-            // blacklisted.
-        }
-    };
-
-    /*
-     * This is a utility method that will throw a <tt>NullPointerException</tt>
-     * in case that the given object is null. The message will be of the form name +
-     * may not be null.
-     */
-    private void checkNull(final Object object, final String name)
-    {
-        if(null == object)
-        {
-            throw new NullPointerException(name + " may not be null");
-        }
-    }
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CacheFilters.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CacheFilters.java
deleted file mode 100644
index 8f04cb4..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CacheFilters.java
+++ /dev/null
@@ -1,91 +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.felix.eventadmin.impl.handler;
-
-import org.apache.felix.eventadmin.impl.util.CacheMap;
-import org.osgi.framework.*;
-
-/**
- * This is an implementation of the <tt>Filters</tt> factory that uses a cache in
- * order to speed-up filter creation.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public class CacheFilters implements Filters
-{
-    // The cache to use
-    private final CacheMap m_cache;
-
-    // The context of the bundle used to create the Filter objects
-    private final BundleContext m_context;
-
-    /**
-     * The constructor of this factory. The cache is used to speed-up filter
-     * creation.
-     *
-     * @param cache The cache to use
-     * @param context The context of the bundle used to create the <tt>Filter</tt>
-     *      objects
-     */
-    public CacheFilters(final CacheMap cache, final BundleContext context)
-    {
-        if(null == cache)
-        {
-            throw new NullPointerException("Cache may not be null");
-        }
-
-        if(null == context)
-        {
-            throw new NullPointerException("Context may not be null");
-        }
-
-        m_cache = cache;
-
-        m_context = context;
-    }
-
-    /**
-     * Create a filter for the given filter string or return the TRUE_FILTER in case
-     * the string is <tt>null</tt>.
-     *
-     * @param filter The filter as a string
-     * @return The <tt>Filter</tt> of the filter string or the TRUE_FILTER if the
-     *      filter string was <tt>null</tt>
-     * @throws InvalidSyntaxException if <tt>BundleContext.createFilter()</tt>
-     *      throws an <tt>InvalidSyntaxException</tt>
-     *
-     * @see org.apache.felix.eventadmin.impl.handler.Filters#createFilter(java.lang.String)
-     */
-    public Filter createFilter(String filter)
-        throws InvalidSyntaxException
-    {
-        Filter result = (Filter) ((null != filter) ? m_cache.get(filter)
-            : TRUE_FILTER);
-
-        if (null == result)
-        {
-            result = m_context.createFilter(filter);
-
-            m_cache.add(filter, result);
-        }
-
-        return result;
-    }
-
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CacheTopicHandlerFilters.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CacheTopicHandlerFilters.java
deleted file mode 100644
index 3047f75..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CacheTopicHandlerFilters.java
+++ /dev/null
@@ -1,113 +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.felix.eventadmin.impl.handler;
-
-import org.apache.felix.eventadmin.impl.util.CacheMap;
-import org.osgi.service.event.EventConstants;
-
-/**
- * The factory for <tt>EventHandler</tt> filters based on a certain topic. This
- * implementation uses a cache to speed-up filter creation.
- * 
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public class CacheTopicHandlerFilters implements TopicHandlerFilters
-{
-    // The cache
-    private final CacheMap m_cache;
-    
-    private final char[] m_keyChars = EventConstants.EVENT_TOPIC.toCharArray();
-    
-    private final char[] m_filterStart;
-    
-    /**
-     * The constructor of the filter factory. 
-     * 
-     * @param cache The cache to use in order to speed-up filter creation.
-     * 
-     * @param requireTopic Include handlers that do not provide a topic
-     */
-    public CacheTopicHandlerFilters(final CacheMap cache, final boolean requireTopic)
-    {
-        if(null == cache)
-        {
-            throw new NullPointerException("Cache may not be null");
-        }
-        
-        m_cache = cache;
-        
-        m_filterStart = ("(|" + 
-            ((requireTopic) ? "" : "(!(" + new String(m_keyChars) + "=*))") +
-            "(" + new String(m_keyChars) + "=\\*)(" + new String(m_keyChars) + 
-            "=").toCharArray();
-    }
-    
-    /**
-     * Create a filter that will match all <tt>EventHandler</tt> services that match
-     * the given topic.
-     * 
-     * @param topic The topic to match
-     * 
-     * @return A filter that will match all <tt>EventHandler</tt> services for 
-     *      the given topic.
-     *      
-     * @see org.apache.felix.eventadmin.impl.handler.TopicHandlerFilters#createFilterForTopic(java.lang.String)
-     */
-    public String createFilterForTopic(String topic)
-    {
-        // build the ldap-query - as a simple example: 
-        // topic=org/apache/felix/TEST
-        // result = (|(topic=\*)(topic=org/\*)(topic=org/apache/\*)
-        //            (topic=org/apache/felix/\*)(topic=org/apache/felix/TEST))
-        String result = (String) m_cache.get(topic);
-        
-        if(null == result)
-        {
-            char[] topicChars = topic.toCharArray();
-
-            final StringBuffer filter = new StringBuffer(topicChars.length
-                * topicChars.length);
-
-            filter.append(m_filterStart);
-
-            for (int i = 0; i < topicChars.length; i++)
-            {
-                if ('/' == topicChars[i])
-                {
-                    filter.append('/').append('\\').append('*').append(')');
-
-                    filter.append('(').append(m_keyChars).append('=').append(
-                        topicChars, 0, i + 1);
-                }
-                else
-                {
-                    filter.append(topicChars[i]);
-                }
-            }
-
-            filter.append(')').append(')');
-
-            result = filter.toString();
-            
-            m_cache.add(topic, result);
-        }
-        
-        return result;
-    }
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CleanBlackList.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CleanBlackList.java
deleted file mode 100644
index 670edb2..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/CleanBlackList.java
+++ /dev/null
@@ -1,84 +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.felix.eventadmin.impl.handler;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.osgi.framework.ServiceReference;
-
-/**
- * This class implements a <tt>BlackList</tt> that removes references to unregistered
- * services automatically.
- * 
- * @see org.apache.felix.eventadmin.impl.handler.BlackList
- * 
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public class CleanBlackList implements BlackList
-{
-    // This set removes stale (i.e., unregistered) references on any call to contains
-    private final Set m_blackList = Collections.synchronizedSet(new HashSet()
-        {
-            public boolean contains(final Object object)
-            {
-                for (Iterator iter = super.iterator(); iter.hasNext();)
-                {
-                    final ServiceReference ref = (ServiceReference) iter.next();
-
-                    if (null == ref.getBundle())
-                    {
-                        iter.remove();
-                    }
-                }
-
-                return super.contains(object);
-            }
-        });
-
-    /**
-     * Add a service to this blacklist.
-     * 
-     * @param ref The reference of the service that is blacklisted
-     * 
-     * @see org.apache.felix.eventadmin.impl.handler.BlackList#add(org.osgi.framework.ServiceReference)
-     */
-    public void add(final ServiceReference ref)
-    {
-        m_blackList.add(ref);
-    }
-
-    /**
-     * Lookup whether a given service is blacklisted.
-     * 
-     * @param ref The reference of the service
-     * 
-     * @return <tt>true</tt> in case that the service reference has been blacklisted, 
-     *      <tt>false</tt> otherwise.
-     * 
-     * @see org.apache.felix.eventadmin.impl.handler.BlackList#contains(org.osgi.framework.ServiceReference)
-     */
-    public boolean contains(final ServiceReference ref)
-    {
-        return m_blackList.contains(ref);
-    }
-
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventAdminImpl.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventAdminImpl.java
new file mode 100644
index 0000000..c714afc
--- /dev/null
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventAdminImpl.java
@@ -0,0 +1,149 @@
+/*
+ * 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.felix.eventadmin.impl.handler;
+
+import org.apache.felix.eventadmin.impl.tasks.*;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * This is the actual implementation of the OSGi R4 Event Admin Service (see the
+ * Compendium 113 for details). The implementation uses a <tt>HandlerTasks</tt>
+ * in order to determine applicable <tt>EventHandler</tt> for a specific event and
+ * subsequently dispatches the event to the handlers via <tt>DeliverTasks</tt>.
+ * To do this, it uses two different <tt>DeliverTasks</tt> one for asynchronous and
+ * one for synchronous event delivery depending on whether its <tt>post()</tt> or
+ * its <tt>send()</tt> method is called. Note that the actual work is done in the
+ * implementations of the <tt>DeliverTasks</tt>. Additionally, a stop method is
+ * provided that prevents subsequent events to be delivered.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventAdminImpl implements EventAdmin
+{
+    /** The tracker for the event handlers. */
+    private volatile EventHandlerTracker tracker;
+
+    // The asynchronous event dispatcher
+    private final AsyncDeliverTasks m_postManager;
+
+    // The synchronous event dispatcher
+    private final SyncDeliverTasks m_sendManager;
+
+    /**
+     * The constructor of the <tt>EventAdmin</tt> implementation.
+     *
+     * @param syncPool The synchronous thread pool
+     * @param asyncPool The asynchronous thread pool
+     */
+    public EventAdminImpl(
+            final BundleContext bundleContext,
+            final DefaultThreadPool syncPool,
+            final DefaultThreadPool asyncPool,
+            final int timeout,
+            final String[] ignoreTimeout,
+            final boolean requireTopic)
+    {
+        checkNull(syncPool, "syncPool");
+        checkNull(asyncPool, "asyncPool");
+
+        this.tracker = new EventHandlerTracker(bundleContext);
+        this.tracker.update(ignoreTimeout, requireTopic);
+        this.tracker.open();
+        m_sendManager = new SyncDeliverTasks(syncPool, timeout);
+        m_postManager = new AsyncDeliverTasks(asyncPool, m_sendManager);
+    }
+
+    /**
+     * Check if the event admin is active and return the tracker
+     * @return The tracker
+     * @throws IllegalArgumentException if the event admin has been stopped
+     */
+    private EventHandlerTracker getTracker() {
+        final EventHandlerTracker localTracker = tracker;
+        if ( localTracker == null ) {
+            throw new IllegalStateException("The EventAdmin is stopped");
+        }
+        return localTracker;
+    }
+
+    /**
+     * Post an asynchronous event.
+     *
+     * @param event The event to be posted by this service
+     *
+     * @throws IllegalStateException - In case we are stopped
+     *
+     * @see org.osgi.service.event.EventAdmin#postEvent(org.osgi.service.event.Event)
+     */
+    public void postEvent(final Event event)
+    {
+        m_postManager.execute(this.getTracker().getHandlers(event), event);
+    }
+
+    /**
+     * Send a synchronous event.
+     *
+     * @param event The event to be send by this service
+     *
+     * @throws IllegalStateException - In case we are stopped
+     *
+     * @see org.osgi.service.event.EventAdmin#sendEvent(org.osgi.service.event.Event)
+     */
+    public void sendEvent(final Event event)
+    {
+        m_sendManager.execute(this.getTracker().getHandlers(event), event);
+    }
+
+    /**
+     * This method can be used to stop the delivery of events.
+     */
+    public void stop()
+    {
+        this.tracker.close();
+        this.tracker = null;
+    }
+
+    /**
+     * Update the event admin with new configuration.
+     */
+    public void update(final int timeout,
+            final String[] ignoreTimeout,
+            final boolean requireTopic)
+    {
+        this.tracker.close();
+        this.tracker.update(ignoreTimeout, requireTopic);
+        this.m_sendManager.update(timeout);
+        this.tracker.open();
+    }
+
+    /**
+     * This is a utility method that will throw a <tt>NullPointerException</tt>
+     * in case that the given object is null. The message will be of the form
+     * "${name} + may not be null".
+     */
+    private void checkNull(final Object object, final String name)
+    {
+        if (null == object)
+        {
+            throw new NullPointerException(name + " may not be null");
+        }
+    }
+}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerProxy.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerProxy.java
new file mode 100644
index 0000000..7216f40
--- /dev/null
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerProxy.java
@@ -0,0 +1,342 @@
+/*
+ * 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.felix.eventadmin.impl.handler;
+
+import org.apache.felix.eventadmin.impl.security.PermissionsUtil;
+import org.apache.felix.eventadmin.impl.util.LogWrapper;
+import org.osgi.framework.*;
+import org.osgi.service.event.*;
+
+/**
+ * This is a proxy for event handlers. It gets the real event handler
+ * on demand and prepares some information for faster processing.
+ *
+ * It checks the timeout handling for the implementation as well as
+ * blacklisting the handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventHandlerProxy {
+
+    /** The service reference for the event handler. */
+    private final ServiceReference reference;
+
+    /** The handler context. */
+    private final EventHandlerTracker.HandlerContext handlerContext;
+
+    /** The event topics. */
+    private volatile String[] topics;
+
+    /** Optional filter. */
+    private volatile Filter filter;
+
+    /** Lazy fetched event handler. */
+    private volatile EventHandler handler;
+
+    /** Is this handler blacklisted? */
+    private volatile boolean blacklisted;
+
+    /** Use timeout. */
+    private boolean useTimeout;
+
+	/**
+	 * Create an EventHandlerProxy.
+     *
+     * @param context The handler context
+	 * @param reference Reference to the EventHandler
+	 */
+	public EventHandlerProxy(final EventHandlerTracker.HandlerContext context,
+	        final ServiceReference reference)
+	{
+	    this.handlerContext = context;
+		this.reference = reference;
+	}
+
+	/**
+	 * Update the state with current properties from the service
+	 * @return <code>true</code> if the handler configuration is valid.
+	 */
+	public boolean update()
+	{
+	    this.blacklisted = false;
+		boolean valid = true;
+		// First check, topic
+        final Object topicObj = reference.getProperty(EventConstants.EVENT_TOPIC);
+        if (topicObj instanceof String)
+        {
+            if ( topicObj.toString().equals("*") )
+            {
+                this.topics = null;
+            }
+            else
+            {
+                this.topics = new String[] {topicObj.toString()};
+            }
+        }
+        else if (topicObj instanceof String[])
+        {
+            // check if one value matches '*'
+            final String[] values = (String[])topicObj;
+            boolean matchAll = false;
+            for(int i=0;i<values.length;i++)
+            {
+                if ( "*".equals(values[i]) )
+                {
+                    matchAll = true;
+                }
+            }
+            if ( matchAll )
+            {
+                this.topics = null;
+            }
+            else
+            {
+                this.topics = values;
+            }
+        }
+        else if ( topicObj == null && !this.handlerContext.requireTopic )
+        {
+            this.topics = null;
+        }
+        else
+        {
+            final String reason;
+            if ( topicObj == null )
+            {
+                reason = "Missing";
+            }
+            else
+            {
+                reason = "Neither of type String nor String[] : " + topicObj.getClass().getName();
+            }
+            LogWrapper.getLogger().log(
+                    this.reference,
+                    LogWrapper.LOG_WARNING,
+                    "Invalid EVENT_TOPICS : " + reason + " - Ignoring ServiceReference ["
+                        + this.reference + " | Bundle("
+                        + this.reference.getBundle() + ")]");
+            this.topics = null;
+            valid = false;
+        }
+        // Second check filter (but only if topics is valid)
+        Filter handlerFilter = null;
+        if ( this.topics != null )
+        {
+            final Object filterObj = reference.getProperty(EventConstants.EVENT_FILTER);
+            if (filterObj instanceof String)
+            {
+                try
+                {
+                    handlerFilter = this.handlerContext.bundleContext.createFilter(filterObj.toString());
+                }
+                catch (final InvalidSyntaxException e)
+                {
+                    valid = false;
+                    LogWrapper.getLogger().log(
+                            this.reference,
+                            LogWrapper.LOG_WARNING,
+                            "Invalid EVENT_FILTER - Ignoring ServiceReference ["
+                                + this.reference + " | Bundle("
+                                + this.reference.getBundle() + ")]", e);
+                }
+            }
+            else if ( filterObj != null )
+            {
+                valid = false;
+                LogWrapper.getLogger().log(
+                        this.reference,
+                        LogWrapper.LOG_WARNING,
+                        "Invalid EVENT_FILTER - Ignoring ServiceReference ["
+                            + this.reference + " | Bundle("
+                            + this.reference.getBundle() + ")]");
+            }
+        }
+        this.filter = handlerFilter;
+
+        // make sure to release the handler
+        this.release();
+
+        return valid;
+	}
+
+	/**
+	 * Dispose the proxy and release the handler
+	 */
+	public void dispose()
+	{
+	    this.release();
+	}
+
+    /**
+     * Get the event handler.
+     */
+    private synchronized EventHandler obtain() {
+        if (this.handler == null)
+        {
+            try
+            {
+                this.handler = (EventHandler)this.handlerContext.bundleContext.getService(this.reference);
+                if ( this.handler != null )
+                {
+                    this.checkTimeout(this.handler.getClass().getName());
+                }
+            }
+            catch (final IllegalStateException ignore)
+            {
+                // event handler might be stopped - ignore
+            }
+        }
+        return this.handler;
+    }
+
+    /**
+	 * Release the handler
+	 */
+	private synchronized void release()
+	{
+		if ( this.handler != null )
+		{
+            try
+            {
+                this.handlerContext.bundleContext.ungetService(this.reference);
+            }
+            catch (final IllegalStateException ignore)
+            {
+                // event handler might be stopped - ignore
+            }
+            this.handler = null;
+		}
+	}
+
+	/**
+	 * Get the topics of this handler.
+	 * If this handler matches all topics <code>null</code> is returned
+	 */
+	public String[] getTopics()
+	{
+	    return this.topics;
+	}
+
+    /**
+     * Check if this handler is allowed to receive the event
+     * - blacklisted
+     * - check filter
+     * - check permission
+     */
+    public boolean canDeliver(final Event event)
+    {
+        if ( this.blacklisted )
+        {
+            return false;
+        }
+        final Bundle bundle = reference.getBundle();
+        // is service unregistered?
+        if (bundle == null)
+        {
+            return false;
+        }
+
+        // filter match
+        final Filter eventFilter = this.filter;
+        if ( eventFilter != null && !event.matches(eventFilter) )
+        {
+            return false;
+        }
+
+        // permission check
+        final Object p = PermissionsUtil.createSubscribePermission(event.getTopic());
+        if (p != null && !bundle.hasPermission(p) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Should a timeout be used for this handler?
+     */
+    public boolean useTimeout()
+    {
+        return this.useTimeout;
+    }
+
+    /**
+     * Check the timeout configuration for this handler.
+     */
+    private void checkTimeout(final String className)
+    {
+        if ( this.handlerContext.ignoreTimeoutMatcher != null )
+        {
+            for(int i=0;i<this.handlerContext.ignoreTimeoutMatcher.length;i++)
+            {
+                if ( this.handlerContext.ignoreTimeoutMatcher[i] != null)
+                {
+                    if ( this.handlerContext.ignoreTimeoutMatcher[i].match(className) )
+                    {
+                        this.useTimeout = false;
+                        return;
+                    }
+                }
+            }
+        }
+        this.useTimeout = true;
+    }
+
+    /**
+	 * Send the event.
+	 */
+	public void sendEvent(final Event event)
+	{
+		final EventHandler handlerService = this.obtain();
+		if (handlerService == null)
+		{
+			return;
+		}
+
+		try
+		{
+			handlerService.handleEvent(event);
+		}
+		catch (final Throwable e)
+		{
+            // The spec says that we must catch exceptions and log them:
+            LogWrapper.getLogger().log(
+                this.reference,
+                LogWrapper.LOG_WARNING,
+                "Exception during event dispatch [" + event + " | "
+                    + this.reference + " | Bundle("
+                    + this.reference.getBundle() + ")]", e);
+		}
+	}
+
+	/**
+	 * Blacklist the handler.
+	 */
+	public void blackListHandler()
+	{
+        LogWrapper.getLogger().log(
+                LogWrapper.LOG_WARNING,
+                "Blacklisting ServiceReference [" + this.reference + " | Bundle("
+                    + this.reference.getBundle() + ")] due to timeout!");
+        this.blacklisted = true;
+        // we can free the handler now.
+        this.release();
+	}
+}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerTracker.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerTracker.java
new file mode 100644
index 0000000..5babd1a
--- /dev/null
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerTracker.java
@@ -0,0 +1,396 @@
+/*
+ * 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.felix.eventadmin.impl.handler;
+
+import java.util.*;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * The event handler tracker keeps track of all event handler services.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventHandlerTracker extends ServiceTracker {
+
+    /** The proxies in this list match all events. */
+	private volatile List matchingAllEvents;
+
+    /** This is a map for exact topic matches. The key is the topic,
+     * the value is a list of proxies.
+     */
+    private volatile Map matchingTopic;
+
+	/** This is a map for wildcard topics. The key is the prefix of the topic,
+	 * the value is a list of proxies
+	 */
+	private volatile Map matchingPrefixTopic;
+
+
+	/** The context for the proxies. */
+	private HandlerContext handlerContext;
+
+    public EventHandlerTracker(final BundleContext context) {
+		super(context, EventHandler.class.getName(), null);
+
+		// we start with empty collections
+		this.matchingAllEvents = new ArrayList();
+		this.matchingTopic = new HashMap();
+		this.matchingPrefixTopic = new HashMap();
+	}
+
+    /**
+     * Update the timeout configuration.
+     * @param ignoreTimeout
+     */
+    public void update(final String[] ignoreTimeout, final boolean requireTopic) {
+        final Matcher[] ignoreTimeoutMatcher;
+        if ( ignoreTimeout == null || ignoreTimeout.length == 0 )
+        {
+            ignoreTimeoutMatcher = null;
+        }
+        else
+        {
+            ignoreTimeoutMatcher = new Matcher[ignoreTimeout.length];
+            for(int i=0;i<ignoreTimeout.length;i++)
+            {
+                String value = ignoreTimeout[i];
+                if ( value != null )
+                {
+                    value = value.trim();
+                }
+                if ( value != null && value.length() > 0 )
+                {
+                    if ( value.endsWith(".") )
+                    {
+                        ignoreTimeoutMatcher[i] = new PackageMatcher(value.substring(0, value.length() - 1));
+                    }
+                    else if ( value.endsWith("*") )
+                    {
+                        ignoreTimeoutMatcher[i] = new SubPackageMatcher(value.substring(0, value.length() - 1));
+                    }
+                    else
+                    {
+                        ignoreTimeoutMatcher[i] = new ClassMatcher(value);
+                    }
+                }
+            }
+        }
+        this.handlerContext = new HandlerContext(this.context, ignoreTimeoutMatcher, requireTopic);
+    }
+
+    /**
+	 * @see org.osgi.util.tracker.ServiceTracker#addingService(org.osgi.framework.ServiceReference)
+	 */
+	public Object addingService(final ServiceReference reference) {
+		final EventHandlerProxy proxy = new EventHandlerProxy(this.handlerContext, reference);
+		if ( proxy.update() ) {
+			this.put(proxy);
+		}
+		return proxy;
+	}
+
+	/**
+	 * @see org.osgi.util.tracker.ServiceTracker#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
+	 */
+	public void modifiedService(final ServiceReference reference, final Object service) {
+	    final EventHandlerProxy proxy = (EventHandlerProxy)service;
+	    this.remove(proxy);
+	    if ( proxy.update() ) {
+            this.put(proxy);
+	    }
+	}
+
+	/**
+	 * @see org.osgi.util.tracker.ServiceTracker#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
+	 */
+	public void removedService(ServiceReference reference, Object service) {
+        final EventHandlerProxy proxy = (EventHandlerProxy)service;
+        this.remove(proxy);
+        proxy.dispose();
+	}
+
+	private void updateMap(final Map proxyListMap, final String key, final EventHandlerProxy proxy, final boolean add) {
+        List proxies = (List)proxyListMap.get(key);
+        if (proxies == null) {
+            if ( !add )
+            {
+                return;
+            }
+            proxies = new ArrayList();
+        } else {
+            proxies = new ArrayList(proxies);
+        }
+        if ( add )
+        {
+            proxies.add(proxy);
+        }
+        else
+        {
+            proxies.remove(proxy);
+        }
+        if ( proxies.size() == 0 )
+        {
+            proxyListMap.remove(key);
+        }
+        else
+        {
+            proxyListMap.put(key, proxies);
+        }
+	}
+
+	/**
+	 * Check the topics of the event handler and put it into the
+	 * corresponding collections.
+	 * We always create new collections - while this is "expensive"
+	 * it allows us to read from them unsynced
+	 */
+	private synchronized void put(final EventHandlerProxy proxy) {
+		final String[] topics = proxy.getTopics();
+		if ( topics == null )
+		{
+		    final List newMatchingAllEvents = new ArrayList(this.matchingAllEvents);
+		    newMatchingAllEvents.add(proxy);
+		    this.matchingAllEvents = newMatchingAllEvents;
+		}
+		else
+		{
+		    Map newMatchingTopic = null;
+		    Map newMatchingPrefixTopic = null;
+    		for(int i = 0; i < topics.length; i++) {
+    			final String topic = topics[i];
+
+    			if ( topic.endsWith("/*") )
+    			{
+                    // prefix topic: we remove the /*
+    			    if ( newMatchingPrefixTopic == null )
+    			    {
+    			        newMatchingPrefixTopic = new HashMap(this.matchingPrefixTopic);
+    			    }
+
+    				final String prefix = topic.substring(0, topic.length() - 2);
+                    this.updateMap(newMatchingPrefixTopic, prefix, proxy, true);
+    			}
+    			else
+    			{
+    			    // exact match
+                    if ( newMatchingTopic == null )
+                    {
+                        newMatchingTopic = new HashMap(this.matchingTopic);
+                    }
+
+                    this.updateMap(newMatchingTopic, topic, proxy, true);
+    			}
+    		}
+    		if ( newMatchingTopic != null )
+    		{
+    		    this.matchingTopic = newMatchingTopic;
+    		}
+    		if ( newMatchingPrefixTopic != null )
+    		{
+    		    this.matchingPrefixTopic = newMatchingPrefixTopic;
+    		}
+		}
+	}
+
+    /**
+     * Check the topics of the event handler and remove it from the
+     * corresponding collections.
+     * We always create new collections - while this is "expensive"
+     * it allows us to read from them unsynced
+     */
+	private synchronized void remove(final EventHandlerProxy proxy) {
+        final String[] topics = proxy.getTopics();
+        if ( topics == null )
+        {
+            final List newMatchingAllEvents = new ArrayList(this.matchingAllEvents);
+            newMatchingAllEvents.remove(proxy);
+            this.matchingAllEvents = newMatchingAllEvents;
+        } else {
+            Map newMatchingTopic = null;
+            Map newMatchingPrefixTopic = null;
+            for(int i = 0; i < topics.length; i++) {
+                final String topic = topics[i];
+
+                if ( topic.endsWith("/*") )
+                {
+                    // prefix topic: we remove the /*
+                    if ( newMatchingPrefixTopic == null )
+                    {
+                        newMatchingPrefixTopic = new HashMap(this.matchingPrefixTopic);
+                    }
+
+                    final String prefix = topic.substring(0, topic.length() - 2);
+                    this.updateMap(newMatchingPrefixTopic, prefix, proxy, false);
+                }
+                else
+                {
+                    // exact match
+                    if ( newMatchingTopic == null )
+                    {
+                        newMatchingTopic = new HashMap(this.matchingTopic);
+                    }
+
+                    this.updateMap(newMatchingTopic, topic, proxy, false);
+                }
+            }
+            if ( newMatchingTopic != null )
+            {
+                this.matchingTopic = newMatchingTopic;
+            }
+            if ( newMatchingPrefixTopic != null )
+            {
+                this.matchingPrefixTopic = newMatchingPrefixTopic;
+            }
+        }
+	}
+
+	/**
+	 * Get all handlers for this event
+	 *
+	 * @param event The event topic
+	 * @return All handlers for the event
+	 */
+	public Collection getHandlers(final Event event) {
+	    final String topic = event.getTopic();
+
+		final Set handlers = new HashSet();
+
+		// Add all handlers matching everything
+		handlers.addAll(this.matchingAllEvents);
+
+		// Now check for prefix matches
+		if ( !this.matchingPrefixTopic.isEmpty() )
+		{
+		    int pos = topic.lastIndexOf('/');
+			while (pos != -1)
+			{
+			    final String prefix = topic.substring(0, pos);
+				List proxies = (List)this.matchingPrefixTopic.get(prefix);
+				if (proxies != null)
+				{
+					handlers.addAll(proxies);
+				}
+
+				pos = prefix.lastIndexOf('/');
+			}
+		}
+
+		// Add the handlers for matching topic names
+		List proxies = (List)this.matchingTopic.get(topic);
+		if (proxies != null) {
+			handlers.addAll(proxies);
+		}
+
+		// now check permission and filters
+		final Iterator i = handlers.iterator();
+		while ( i.hasNext() ) {
+		    final EventHandlerProxy proxy = (EventHandlerProxy) i.next();
+		    if ( !proxy.canDeliver(event) ) {
+		        i.remove();
+		    }
+		}
+		return handlers;
+	}
+
+    /**
+     * The matcher interface for checking if timeout handling
+     * is disabled for the handler.
+     * Matching is based on the class name of the event handler.
+     */
+    static interface Matcher
+    {
+        boolean match(String className);
+    }
+
+    /** Match a package. */
+    private static final class PackageMatcher implements Matcher
+    {
+        private final String m_packageName;
+
+        public PackageMatcher(final String name)
+        {
+            m_packageName = name;
+        }
+        public boolean match(String className)
+        {
+            final int pos = className.lastIndexOf('.');
+            return pos > -1 && className.substring(0, pos).equals(m_packageName);
+        }
+    }
+
+    /** Match a package or sub package. */
+    private static final class SubPackageMatcher implements Matcher
+    {
+        private final String m_packageName;
+
+        public SubPackageMatcher(final String name)
+        {
+            m_packageName = name + '.';
+        }
+        public boolean match(String className)
+        {
+            final int pos = className.lastIndexOf('.');
+            return pos > -1 && className.substring(0, pos + 1).startsWith(m_packageName);
+        }
+    }
+
+    /** Match a class name. */
+    private static final class ClassMatcher implements Matcher
+    {
+        private final String m_className;
+
+        public ClassMatcher(final String name)
+        {
+            m_className = name;
+        }
+        public boolean match(String className)
+        {
+            return m_className.equals(className);
+        }
+    }
+
+    /**
+     * The context object passed to the proxies.
+     */
+    static final class HandlerContext
+    {
+        /** The bundle context. */
+        public final BundleContext bundleContext;
+
+        /** The matchers for ignore timeout handling. */
+        public final Matcher[] ignoreTimeoutMatcher;
+
+        /** Is a topic required. */
+        public final boolean requireTopic;
+
+        public HandlerContext(final BundleContext bundleContext,
+                final Matcher[] ignoreTimeoutMatcher,
+                final boolean   requireTopic)
+        {
+            this.bundleContext = bundleContext;
+            this.ignoreTimeoutMatcher = ignoreTimeoutMatcher;
+            this.requireTopic = requireTopic;
+        }
+    }
+}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/Filters.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/Filters.java
deleted file mode 100644
index 40ee69d..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/Filters.java
+++ /dev/null
@@ -1,86 +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.felix.eventadmin.impl.handler;
-
-import java.util.Dictionary;
-
-import org.osgi.framework.*;
-
-/**
- * The factory for <tt>Filter</tt> objects. Additionally, two null filter objects
- * are provided that either always return <tt>true</tt> or <tt>false</tt>,
- * respectively.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public interface Filters
-{
-    /**
-     * A null filter object that matches any given service reference.
-     */
-    Filter TRUE_FILTER = new Filter()
-    {
-
-        /**
-         * This is a null object that always returns <tt>true</tt>.
-         *
-         * @param reference An unused service reference
-         * @return <tt>true</tt>
-         */
-        public boolean match(final ServiceReference reference)
-        {
-            return true;
-        }
-
-        /**
-         * This is a null object that always returns <tt>true</tt>.
-         *
-         * @param dictionary An unused dictionary
-         * @return <tt>true</tt>
-         */
-        public boolean match(final Dictionary dictionary)
-        {
-            return true;
-        }
-
-        /**
-         * This is a null object that always returns <tt>true</tt>.
-         *
-         * @param dictionary An unused dictionary.
-         * @return <tt>true</tt>
-         */
-        public boolean matchCase(final Dictionary dictionary)
-        {
-            return true;
-        }
-    };
-
-    /**
-     * Create a filter for the given filter string or return the TRUE_FILTER in case
-     * the string is <tt>null</tt>.
-     *
-     * @param filter The filter as a string
-     * @return The <tt>Filter</tt> of the filter string or the TRUE_FILTER if the
-     *      filter string was null
-     * @throws InvalidSyntaxException if <tt>BundleContext.createFilter()</tt>
-     *      throws an <tt>InvalidSyntaxException</tt>
-     */
-    Filter createFilter(final String filter)
-        throws InvalidSyntaxException;
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/HandlerTasks.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/HandlerTasks.java
deleted file mode 100644
index 8b51af9..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/HandlerTasks.java
+++ /dev/null
@@ -1,42 +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.felix.eventadmin.impl.handler;
-
-import java.util.List;
-
-import org.osgi.service.event.Event;
-
-/**
- * The factory for event handler tasks. Implementations of this interface can be
- * used to create tasks that handle the delivery of events to event handlers.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public interface HandlerTasks
-{
-    /**
-     * Create the handler tasks for the event. All matching event handlers must
-     * be determined and delivery tasks for them returned.
-     *
-     * @param event The event for which' handlers delivery tasks must be created
-     *
-     * @return A delivery task for each handler that matches the given event
-     */
-   List createHandlerTasks(final Event event);
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/TopicHandlerFilters.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/TopicHandlerFilters.java
deleted file mode 100644
index c55c742..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/TopicHandlerFilters.java
+++ /dev/null
@@ -1,38 +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.felix.eventadmin.impl.handler;
-
-/**
- * The factory for <tt>EventHandler</tt> filters based on a certain topic.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public interface TopicHandlerFilters
-{
-    /**
-     * Create a filter that will match all <tt>EventHandler</tt> services that match
-     * the given topic.
-     *
-     * @param topic The topic to match
-     *
-     * @return A filter that will match all <tt>EventHandler</tt> services for
-     *      the given topic.
-     */
-    String createFilterForTopic(final String topic);
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/EventAdminSecurityDecorator.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/EventAdminSecurityDecorator.java
index 537047e..a1c0e19 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/EventAdminSecurityDecorator.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/EventAdminSecurityDecorator.java
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.eventadmin.impl.security;
 
+import java.security.Permission;
+
 import org.osgi.framework.Bundle;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
@@ -128,7 +130,7 @@
         return m_admin.equals(o);
     }
 
-    /*
+    /**
      * This is a utility method that will throw a <tt>SecurityExcepiton</tt> in case
      * that the given bundle (i.e, the caller) has not appropriate permissions to
      * publish to this topic. This method uses Bundle.hasPermission() and the given
@@ -136,7 +138,8 @@
      */
     private void checkPermission(final String topic)
     {
-        if(!m_bundle.hasPermission(PermissionsUtil.createPublishPermission(topic)))
+        final Permission p = PermissionsUtil.createPublishPermission(topic);
+        if(p != null && !m_bundle.hasPermission(p))
         {
             throw new SecurityException("Bundle[" + m_bundle +
                 "] has no PUBLISH permission for topic [" + topic + "]");
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/PermissionsUtil.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/PermissionsUtil.java
index 240d363..3bcccd7 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/PermissionsUtil.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/PermissionsUtil.java
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.eventadmin.impl.security;
 
+import java.security.Permission;
+
 import org.osgi.service.event.TopicPermission;
 
 /**
@@ -27,74 +29,61 @@
  */
 public abstract class PermissionsUtil
 {
+    /** Marker if permission created failed. */
+    private static volatile boolean createPermissions = true;
+
     /**
      * Creates a <tt>TopicPermission</tt> for the given topic and the type PUBLISH
-     * Note that a
-     * <tt>java.lang.Object</tt> is returned in case creating a new TopicPermission
-     * fails. This assumes that Bundle.hasPermission is used in order to evaluate the
-     * created Permission which in turn will return true if security is not supported
-     * by the framework. Otherwise, it will return false due to receiving something
-     * that is not a subclass of <tt>java.lang.SecurityPermission</tt> hence, this
-     * combination ensures that access is granted in case a topic permission could
-     * not be created due to missing security support by the framework.
      *
      * @param topic The target topic
      *
-     * @return The created permission or a <tt>java.lang.Object</tt> in case the
-     *      permission could not be created.
+     * @return The created permission or <tt>null</tt> in case the
+     *         permission could not be created.
      *
      * @see org.osgi.service.event.TopicPermission
      */
-    public static Object createPublishPermission(final String topic)
+    public static Permission createPublishPermission(final String topic)
     {
-        Object result;
-        try
+        if ( createPermissions )
         {
-            result = new org.osgi.service.event.TopicPermission(topic, TopicPermission.PUBLISH);
-        } catch (Throwable t)
-        {
-            // This might happen in case security is not supported
-            // Bundle.hasPermission will return true in this case
-            // hence topicPermission = new Object() is o.k.
-
-            result = new Object();
+            try
+            {
+                return new org.osgi.service.event.TopicPermission(topic, TopicPermission.PUBLISH);
+            }
+            catch (Throwable t)
+            {
+                // This might happen in case security is not supported
+                createPermissions = false;
+            }
         }
-        return result;
+        return null;
     }
 
     /**
      * Creates a <tt>TopicPermission</tt> for the given topic and the type SUBSCRIBE
      * Note that a
-     * <tt>java.lang.Object</tt> is returned in case creating a new TopicPermission
-     * fails. This assumes that Bundle.hasPermission is used in order to evaluate the
-     * created Permission which in turn will return true if security is not supported
-     * by the framework. Otherwise, it will return false due to receiving something
-     * that is not a subclass of <tt>java.lang.SecurityPermission</tt> hence, this
-     * combination ensures that access is granted in case a topic permission could
-     * not be created due to missing security support by the framework.
      *
      * @param topic The target topic
      *
-     * @return The created permission or a <tt>java.lang.Object</tt> in case the
+     * @return The created permission or a <tt>null</tt> in case the
      *      permission could not be created.
      *
      * @see org.osgi.service.event.TopicPermission
      */
-    public static Object createSubscribePermission(final String topic)
+    public static Permission createSubscribePermission(final String topic)
     {
-        Object result;
-        try
+        if ( createPermissions )
         {
-            result = new org.osgi.service.event.TopicPermission(topic, TopicPermission.SUBSCRIBE);
-        } catch (Throwable t)
-        {
-            // This might happen in case security is not supported
-            // Bundle.hasPermission will return true in this case
-            // hence topicPermission = new Object() is o.k.
-
-            result = new Object();
+            try
+            {
+                return new org.osgi.service.event.TopicPermission(topic, TopicPermission.SUBSCRIBE);
+            }
+            catch (Throwable t)
+            {
+                // This might happen in case security is not supported
+                createPermissions = false;
+            }
         }
-        return result;
+        return null;
     }
-
 }
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/AsyncDeliverTasks.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/AsyncDeliverTasks.java
index 19a1e13..e3653f8 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/AsyncDeliverTasks.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/AsyncDeliverTasks.java
@@ -20,14 +20,14 @@
 
 import java.util.*;
 
-import org.apache.felix.eventadmin.impl.dispatch.DefaultThreadPool;
+import org.osgi.service.event.Event;
 
 /**
  * This class does the actual work of the asynchronous event dispatch.
  *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class AsyncDeliverTasks implements DeliverTask
+public class AsyncDeliverTasks
 {
     /** The thread pool to use to spin-off new threads. */
     private final DefaultThreadPool m_pool;
@@ -36,7 +36,7 @@
      * is the sync deliver tasks as this has all the code for timeout
      * handling etc.
      */
-    private final DeliverTask m_deliver_task;
+    private final SyncDeliverTasks m_deliver_task;
 
     /** A map of running threads currently delivering async events. */
     private final Map m_running_threads = new HashMap();
@@ -49,7 +49,7 @@
      *      dispatching thread is used to send a synchronous event
      * @param deliverTask The deliver tasks for dispatching the event.
      */
-    public AsyncDeliverTasks(final DefaultThreadPool pool, final DeliverTask deliverTask)
+    public AsyncDeliverTasks(final DefaultThreadPool pool, final SyncDeliverTasks deliverTask)
     {
         m_pool = pool;
         m_deliver_task = deliverTask;
@@ -60,9 +60,8 @@
      *
      * @param tasks The event handler dispatch tasks to execute
      *
-     * @see org.apache.felix.eventadmin.impl.tasks.DeliverTask#execute(org.apache.felix.eventadmin.impl.tasks.HandlerTask[])
      */
-    public void execute(final List tasks)
+    public void execute(final Collection tasks, final Event event)
     {
         final Thread currentThread = Thread.currentThread();
         TaskExecuter executer = null;
@@ -71,11 +70,11 @@
             TaskExecuter runningExecutor = (TaskExecuter)m_running_threads.get(currentThread);
             if ( runningExecutor != null )
             {
-                runningExecutor.add(tasks);
+                runningExecutor.add(tasks, event);
             }
             else
             {
-                executer = new TaskExecuter( tasks, currentThread );
+                executer = new TaskExecuter( tasks, event, currentThread );
                 m_running_threads.put(currentThread, executer);
             }
         }
@@ -91,10 +90,10 @@
 
         private final Object m_key;
 
-        public TaskExecuter(final List tasks, final Object key)
+        public TaskExecuter(final Collection tasks, final Event event, final Object key)
         {
             m_key = key;
-            m_tasks.add(tasks);
+            m_tasks.add(new Object[] {tasks, event});
         }
 
         public void run()
@@ -102,12 +101,12 @@
             boolean running;
             do
             {
-                List tasks = null;
+                Object[] tasks = null;
                 synchronized ( m_tasks )
                 {
-                    tasks = (List) m_tasks.remove(0);
+                    tasks = (Object[]) m_tasks.remove(0);
                 }
-                m_deliver_task.execute(tasks);
+                m_deliver_task.execute((Collection)tasks[0], (Event)tasks[1]);
                 synchronized ( m_running_threads )
                 {
                     running = m_tasks.size() > 0;
@@ -119,11 +118,11 @@
             } while ( running );
         }
 
-        public void add(final List tasks)
+        public void add(final Collection tasks, final Event event)
         {
             synchronized ( m_tasks )
             {
-                m_tasks.add(tasks);
+                m_tasks.add(new Object[] {tasks, event});
             }
         }
     }
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/dispatch/DefaultThreadPool.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DefaultThreadPool.java
similarity index 94%
rename from eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/dispatch/DefaultThreadPool.java
rename to eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DefaultThreadPool.java
index 7e7ed55..7facee1 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/dispatch/DefaultThreadPool.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DefaultThreadPool.java
@@ -14,9 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.eventadmin.impl.dispatch;
+package org.apache.felix.eventadmin.impl.tasks;
 
-import org.apache.felix.eventadmin.impl.tasks.SyncThread;
 import org.apache.felix.eventadmin.impl.util.LogWrapper;
 
 import EDU.oswego.cs.dl.util.concurrent.*;
@@ -95,13 +94,13 @@
      * Execute the task in a free thread or create a new one.
      * @param task The task to execute
      */
-    public void executeTask(Runnable task)
+    public void executeTask(final Runnable task)
     {
         try
         {
             super.execute(task);
         }
-        catch (Throwable t)
+        catch (final Throwable t)
         {
             LogWrapper.getLogger().log(
                     LogWrapper.LOG_WARNING,
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DeliverTask.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DeliverTask.java
deleted file mode 100644
index 216a8b2..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DeliverTask.java
+++ /dev/null
@@ -1,36 +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.felix.eventadmin.impl.tasks;
-
-import java.util.List;
-
-/**
- * Dispatch given event dispatch tasks.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public interface DeliverTask
-{
-    /**
-     * Dispatch the given event dispatch tasks.
-     *
-     * @param handlerTasks The event dispatch tasks to execute
-     */
-    public void execute(List handlerTasks);
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTask.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTask.java
deleted file mode 100644
index 613d74d..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTask.java
+++ /dev/null
@@ -1,43 +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.felix.eventadmin.impl.tasks;
-
-/**
- * A task that will deliver its event to its <tt>EventHandler</tt> when executed
- * or blacklist the handler, respectively.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public interface HandlerTask
-{
-    /**
-     * Return the class name of the handler
-     */
-    String getHandlerClassName();
-
-    /**
-     * Deliver the event to the handler.
-     */
-    void execute();
-
-    /**
-     * Blacklist the handler.
-     */
-    void blackListHandler();
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTaskImpl.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTaskImpl.java
deleted file mode 100644
index e5b3c03..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTaskImpl.java
+++ /dev/null
@@ -1,113 +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.felix.eventadmin.impl.tasks;
-
-import org.apache.felix.eventadmin.impl.handler.BlacklistingHandlerTasks;
-import org.apache.felix.eventadmin.impl.util.LogWrapper;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
-
-/**
- * An implementation of the <tt>HandlerTask</tt> interface.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public class HandlerTaskImpl implements HandlerTask
-{
-    // The service reference of the handler
-    private final ServiceReference m_eventHandlerRef;
-
-    // The event to deliver to the handler
-    private final Event m_event;
-
-    // Used to blacklist the service or get the service object for the reference
-    private final BlacklistingHandlerTasks m_handlerTasks;
-
-    /**
-     * Construct a delivery task for the given service and event.
-     *
-     * @param eventHandlerRef The servicereference of the handler
-     * @param event The event to deliver
-     * @param handlerTasks Used to blacklist the service or get the service object
-     *      for the reference
-     */
-    public HandlerTaskImpl(final ServiceReference eventHandlerRef,
-        final Event event, final BlacklistingHandlerTasks handlerTasks)
-    {
-        m_eventHandlerRef = eventHandlerRef;
-
-        m_event = event;
-
-        m_handlerTasks = handlerTasks;
-    }
-
-    /**
-     * @see org.apache.felix.eventadmin.impl.tasks.HandlerTask#getHandlerClassName()
-     */
-    public String getHandlerClassName()
-    {
-        final EventHandler handler = m_handlerTasks.getEventHandler(m_eventHandlerRef);
-        try
-        {
-            return handler.getClass().getName();
-        }
-        finally
-        {
-            m_handlerTasks.ungetEventHandler(handler, m_eventHandlerRef);
-        }
-    }
-
-    /**
-     * @see org.apache.felix.eventadmin.impl.tasks.HandlerTask#execute()
-     */
-    public void execute()
-    {
-        // Get the service object
-        final EventHandler handler = m_handlerTasks
-            .getEventHandler(m_eventHandlerRef);
-
-        try
-        {
-            handler.handleEvent(m_event);
-        }
-        catch (final Throwable e)
-        {
-            // The spec says that we must catch exceptions and log them:
-            LogWrapper.getLogger().log(
-                m_eventHandlerRef,
-                LogWrapper.LOG_WARNING,
-                "Exception during event dispatch [" + m_event + " | "
-                    + m_eventHandlerRef + " | Bundle("
-                    + m_eventHandlerRef.getBundle() + ")]", e);
-        }
-        finally
-        {
-            m_handlerTasks.ungetEventHandler(handler, m_eventHandlerRef);
-        }
-    }
-
-    /**
-     * @see org.apache.felix.eventadmin.impl.tasks.HandlerTask#blackListHandler()
-     */
-    public void blackListHandler()
-    {
-        m_handlerTasks.blackList(m_eventHandlerRef);
-    }
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
index 875accc..a06f2c8 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
@@ -18,10 +18,11 @@
  */
 package org.apache.felix.eventadmin.impl.tasks;
 
+import java.util.Collection;
 import java.util.Iterator;
-import java.util.List;
 
-import org.apache.felix.eventadmin.impl.dispatch.DefaultThreadPool;
+import org.apache.felix.eventadmin.impl.handler.EventHandlerProxy;
+import org.osgi.service.event.Event;
 
 import EDU.oswego.cs.dl.util.concurrent.TimeoutException;
 
@@ -52,119 +53,30 @@
  *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class SyncDeliverTasks implements DeliverTask
+public class SyncDeliverTasks
 {
+
     /** The thread pool used to spin-off new threads. */
-    final DefaultThreadPool m_pool;
+    private final DefaultThreadPool pool;
 
-    /** The timeout for event handlers, 0 = disabled. */
-    long m_timeout;
-
-    /**
-     * The matcher interface for checking if timeout handling
-     * is disabled for the handler.
-     * Matching is based on the class name of the event handler.
-     */
-    private static interface Matcher
-    {
-        boolean match(String className);
-    }
-
-    /** Match a package. */
-    private static final class PackageMatcher implements Matcher
-    {
-        private final String m_packageName;
-
-        public PackageMatcher(final String name)
-        {
-            m_packageName = name;
-        }
-        public boolean match(String className)
-        {
-            final int pos = className.lastIndexOf('.');
-            return pos > -1 && className.substring(0, pos).equals(m_packageName);
-        }
-    }
-
-    /** Match a package or sub package. */
-    private static final class SubPackageMatcher implements Matcher
-    {
-        private final String m_packageName;
-
-        public SubPackageMatcher(final String name)
-        {
-            m_packageName = name + '.';
-        }
-        public boolean match(String className)
-        {
-            final int pos = className.lastIndexOf('.');
-            return pos > -1 && className.substring(0, pos + 1).startsWith(m_packageName);
-        }
-    }
-
-    /** Match a class name. */
-    private static final class ClassMatcher implements Matcher
-    {
-        private final String m_className;
-
-        public ClassMatcher(final String name)
-        {
-            m_className = name;
-        }
-        public boolean match(String className)
-        {
-            return m_className.equals(className);
-        }
-    }
-
-    /** The matchers for ignore timeout handling. */
-    private Matcher[] m_ignoreTimeoutMatcher;
+    private long timeout;
 
     /**
      * Construct a new sync deliver tasks.
      * @param pool The thread pool used to spin-off new threads.
-     * @param timeout The timeout for an event handler, 0 = disabled
      */
-    public SyncDeliverTasks(final DefaultThreadPool pool, final long timeout, final String[] ignoreTimeout)
+    public SyncDeliverTasks(final DefaultThreadPool pool, final long timeout)
     {
-        m_pool = pool;
-        update(timeout, ignoreTimeout);
+        this.pool = pool;
+        this.update(timeout);
     }
 
-    public void update(final long timeout, final String[] ignoreTimeout) {
-        m_timeout = timeout;
-        if ( ignoreTimeout == null || ignoreTimeout.length == 0 )
-        {
-            m_ignoreTimeoutMatcher = null;
-        }
-        else
-        {
-            Matcher[] ignoreTimeoutMatcher = new Matcher[ignoreTimeout.length];
-            for(int i=0;i<ignoreTimeout.length;i++)
-            {
-                String value = ignoreTimeout[i];
-                if ( value != null )
-                {
-                    value = value.trim();
-                }
-                if ( value != null && value.length() > 0 )
-                {
-                    if ( value.endsWith(".") )
-                    {
-                        ignoreTimeoutMatcher[i] = new PackageMatcher(value.substring(0, value.length() - 1));
-                    }
-                    else if ( value.endsWith("*") )
-                    {
-                        ignoreTimeoutMatcher[i] = new SubPackageMatcher(value.substring(0, value.length() - 1));
-                    }
-                    else
-                    {
-                        ignoreTimeoutMatcher[i] = new ClassMatcher(value);
-                    }
-                }
-            }
-            m_ignoreTimeoutMatcher = ignoreTimeoutMatcher;
-        }
+    /**
+     * Update the timeout configuration
+     */
+    public void update(final long timeout)
+    {
+        this.timeout = timeout;
     }
 
     /**
@@ -172,27 +84,12 @@
      * task.
      * @param tasks The event handler dispatch tasks to execute
      */
-    private boolean useTimeout(final HandlerTask task)
+    private boolean useTimeout(final EventHandlerProxy proxy)
     {
-        // we only check the classname if a timeout is configured
-        if ( m_timeout > 0)
+        // we only check the proxy if a timeout is configured
+        if ( this.timeout > 0)
         {
-            final Matcher[] ignoreTimeoutMatcher = m_ignoreTimeoutMatcher;
-            if ( ignoreTimeoutMatcher != null )
-            {
-                final String className = task.getHandlerClassName();
-                for(int i=0;i<ignoreTimeoutMatcher.length;i++)
-                {
-                    if ( ignoreTimeoutMatcher[i] != null)
-                    {
-                        if ( ignoreTimeoutMatcher[i].match(className) )
-                        {
-                            return false;
-                        }
-                    }
-                }
-            }
-            return true;
+            return proxy.useTimeout();
         }
         return false;
     }
@@ -203,9 +100,8 @@
      *
      * @param tasks The event handler dispatch tasks to execute
      *
-     * @see org.apache.felix.eventadmin.impl.tasks.DeliverTask#execute(List)
      */
-    public void execute(final List tasks)
+    public void execute(final Collection tasks, final Event event)
     {
         final Thread sleepingThread = Thread.currentThread();
         final SyncThread syncThread = sleepingThread instanceof SyncThread ? (SyncThread)sleepingThread : null;
@@ -213,20 +109,20 @@
         final Iterator i = tasks.iterator();
         while ( i.hasNext() )
         {
-            final HandlerTask task = (HandlerTask)i.next();
+            final EventHandlerProxy task = (EventHandlerProxy)i.next();
 
             if ( !useTimeout(task) )
             {
                 // no timeout, we can directly execute
-                task.execute();
+                task.sendEvent(event);
             }
             else if ( syncThread != null )
             {
                 // if this is a cascaded event, we directly use this thread
                 // otherwise we could end up in a starvation
                 final long startTime = System.currentTimeMillis();
-                task.execute();
-                if ( System.currentTimeMillis() - startTime > m_timeout )
+                task.sendEvent(event);
+                if ( System.currentTimeMillis() - startTime > this.timeout )
                 {
                     task.blackListHandler();
                 }
@@ -235,7 +131,7 @@
             {
                 final Rendezvous startBarrier = new Rendezvous();
                 final Rendezvous timerBarrier = new Rendezvous();
-                m_pool.executeTask(new Runnable()
+                this.pool.executeTask(new Runnable()
                 {
                     public void run()
                     {
@@ -244,7 +140,7 @@
                             // notify the outer thread to start the timer
                             startBarrier.waitForRendezvous();
                             // execute the task
-                            task.execute();
+                            task.sendEvent(event);
                             // stop the timer
                             timerBarrier.waitForRendezvous();
                         }
@@ -262,7 +158,7 @@
                 // if someone wakes us up it's the finished inner task
                 try
                 {
-                    timerBarrier.waitAttemptForRendezvous(m_timeout);
+                    timerBarrier.waitAttemptForRendezvous(this.timeout);
                 }
                 catch (final TimeoutException ie)
                 {
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/CacheMap.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/CacheMap.java
deleted file mode 100644
index 13bbbf9..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/CacheMap.java
+++ /dev/null
@@ -1,67 +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.felix.eventadmin.impl.util;
-
-/**
- * This is the interface of a simple cache map. 
- * 
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public interface CacheMap
-{
-    /**
-     * Return the value for the key in case there is one in the cache.
-     * 
-     * @param key The key to look-up
-     * 
-     * @return The value for the given key in case there is one in the cache, 
-     *      <tt>null</tt> otherwise
-     */
-    public Object get(final Object key);
-    
-    /**
-     * Add a value for the key to this cache.
-     * 
-     * @param key The key for the value
-     * @param value The value to add to the cache 
-     */
-    public void add(final Object key, final Object value);
-    
-    /**
-     * Remove a key and its value from the cache.
-     * 
-     * @param key The key to remove
-     * 
-     * @return The value of the key in case there is one in the cache, <tt>null</tt>
-     *      otherwise
-     */
-    public Object remove(final Object key);
-    
-    /**
-     * Returns the number of key-value pairs in this cache.
-     * 
-     * @return The number of key-value pairs in this cache
-     */
-    public int size();
-    
-    /**
-     * Remove all entries of the cache.
-     */
-    public void clear();
-}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/LeastRecentlyUsedCacheMap.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/LeastRecentlyUsedCacheMap.java
deleted file mode 100644
index ca69fb3..0000000
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/LeastRecentlyUsedCacheMap.java
+++ /dev/null
@@ -1,188 +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.felix.eventadmin.impl.util;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This class implements a least recently used cache map. It will hold 
- * a given size of key-value pairs and drop the least recently used entry once this
- * size is reached. This class is thread safe.
- * 
- * @see org.apache.felix.eventadmin.impl.util.CacheMap
- * 
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public class LeastRecentlyUsedCacheMap implements CacheMap
-{
-    // The internal lock for this object used instead synchronized(this)
-    private final Object m_lock = new Object();
-    
-    // The max number of entries in the cache. Once reached entries are replaced
-    private final int m_maxSize;
-    
-    // The cache 
-    private final Map m_cache;
-    
-    // The history used to determine the least recently used entries. The end of the
-    // list is the most recently used key. In other words m_history.get(0) returns
-    // the least recently used key.
-    private final List m_history;
-    
-    /**
-     * The constructor of the cache. The given max size will be used to determine the
-     * size of the cache that triggers replacing least recently used entries with 
-     * new ones.
-     * 
-     * @param maxSize The max number of entries in the cache
-     */
-    public LeastRecentlyUsedCacheMap(final int maxSize)
-    {
-        if(0 >= maxSize)
-        {
-            throw new IllegalArgumentException("Size must be positive");
-        }
-        
-        m_maxSize = maxSize;
-        
-        // We need one more entry then m_maxSize in the cache and a HashMap is
-        // expanded when it reaches 3/4 of its size hence, the funny numbers.
-        m_cache = new HashMap(m_maxSize + 1 + ((m_maxSize + 1) * 3) / 4);
-        
-        // This is like above but assumes a list is expanded when it reaches 1/2 of
-        // its size. Not much harm if this is not the case. 
-        m_history  = new ArrayList(m_maxSize + 1 + ((m_maxSize + 1) / 2));
-    }
-    
-    /**
-     * Returns the value for the key in case there is one. Additionally, the 
-     * LRU counter for the key is updated.
-     * 
-     * @param key The key for the value to return
-     * 
-     * @return The value of the key in case there is one, <tt>null</tt> otherwise
-     * 
-     * @see org.apache.felix.eventadmin.impl.util.CacheMap#get(java.lang.Object)
-     */
-    public Object get(final Object key)
-    {
-        synchronized(m_lock)
-        {
-            final Object result = m_cache.get(key);
-            
-            if(null != result)
-            {
-                m_history.remove(key);
-                
-                m_history.add(key);
-            }
-            
-            return result;
-        }
-    }
-
-    /**
-     * Add the key-value pair to the cache. The key will be come the most recently
-     * used entry. In case max size is (or has been) reached this will remove the
-     * least recently used entry in the cache. In case that the cache already 
-     * contains this specific key-value pair it LRU counter is updated only.
-     * 
-     * @param key The key for the value
-     * @param value The value for the key
-     * 
-     * @see org.apache.felix.eventadmin.impl.util.CacheMap#add(java.lang.Object, java.lang.Object)
-     */
-    public void add(final Object key, final Object value)
-    {
-        synchronized(m_lock)
-        {
-            final Object result = m_cache.put(key, value);
-            
-            if(null != result)
-            {
-                m_history.remove(key);
-            }
-            
-            m_history.add(key);
-            
-            if(m_maxSize < m_cache.size())
-            {
-                m_cache.remove(m_history.remove(0));
-            }
-        }
-    }
-
-    /**
-     * Remove the entry denoted by key from the cache and return its value.
-     * 
-     * @param key The key of the entry to be removed
-     * 
-     * @return The value of the entry removed, <tt>null</tt> if none
-     * 
-     * @see org.apache.felix.eventadmin.impl.util.CacheMap#remove(java.lang.Object)
-     */
-    public Object remove(final Object key)
-    {
-        synchronized(m_lock)
-        {
-            final Object result = m_cache.remove(key);
-            
-            if(null != result)
-            {
-                m_history.remove(key);
-            }
-            
-            return result;
-        }
-    }
-
-    /**
-     * Return the current size of the cache.
-     * 
-     * @return The number of entries currently in the cache.
-     * 
-     * @see org.apache.felix.eventadmin.impl.util.CacheMap#size()
-     */
-    public int size()
-    {
-        synchronized (m_lock)
-        {
-            return m_cache.size();
-        }
-    }
-
-    /**
-     * Remove all entries from the cache.
-     * 
-     * @see org.apache.felix.eventadmin.impl.util.CacheMap#clear()
-     */
-    public void clear()
-    {
-        synchronized (m_lock)
-        {
-            m_cache.clear();
-            
-            m_history.clear();
-        }
-    }
-
-}