FELIX-2020 : Make event admin configurable through configuration admin
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@905932 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/eventadmin/impl/pom.xml b/eventadmin/impl/pom.xml
index b202312..d504124 100644
--- a/eventadmin/impl/pom.xml
+++ b/eventadmin/impl/pom.xml
@@ -67,7 +67,23 @@
<DynamicImport-Package>
org.osgi.service.log
</DynamicImport-Package>
- <Import-Package>!org.osgi.service.log,*</Import-Package>
+ <Import-Package>
+ !org.osgi.service.log,
+ <!--
+ Configuration Admin is optional and if it is
+ present, version 1.2 (from R4.0) is enough
+ -->
+ org.osgi.service.cm;version="[1.2,2)";resolution:=optional,
+
+ <!--
+ Metatype is optional and if it is
+ present, version 1.1 (from R4.1) is enough
+ -->
+ org.osgi.service.metatype;version="[1.1,2)";resolution:=optional,
+
+ <!-- default -->
+ *
+ </Import-Package>
<Export-Package>org.osgi.service.event</Export-Package>
<Private-Package>org.apache.felix.eventadmin.impl.*</Private-Package>
<Import-Service>
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Activator.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Activator.java
index 855a27e..8277851 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Activator.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Activator.java
@@ -18,17 +18,9 @@
*/
package org.apache.felix.eventadmin.impl;
-import org.apache.felix.eventadmin.impl.adapter.*;
-import org.apache.felix.eventadmin.impl.dispatch.DefaultThreadPool;
-import org.apache.felix.eventadmin.impl.dispatch.ThreadPool;
-import org.apache.felix.eventadmin.impl.handler.*;
-import org.apache.felix.eventadmin.impl.security.*;
-import org.apache.felix.eventadmin.impl.tasks.*;
-import org.apache.felix.eventadmin.impl.util.LeastRecentlyUsedCacheMap;
import org.apache.felix.eventadmin.impl.util.LogWrapper;
-import org.osgi.framework.*;
-import org.osgi.service.event.EventAdmin;
-import org.osgi.service.event.TopicPermission;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
/**
* The activator of the EventAdmin bundle. This class registers an implementation of
@@ -37,46 +29,8 @@
* asynchronous and synchronous event-dispatching (as a spec conform optional
* extension).
*
- * The service knows about the following properties which are read at bundle startup:
+ * @see Configuration For configuration features of the event admin.
*
- * <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>
- * The default value is 10. Increase in case of a large amount of synchronous events
- * where the <tt>EventHandler</tt> services in turn send new synchronous events in
- * the event dispatching thread or a lot of timeouts are to be expected. A value of
- * less then 2 triggers the default value. A value of 2 effectively disables thread
- * pooling.
- * </p>
- * <p>
- * <p>
- * <tt>org.apache.felix.eventadmin.Timeout</tt> - The black-listing timeout in
- * milliseconds
- * </p>
- * The default value is 5000. Increase or decrease at own discretion. A value of less
- * then 100 turns timeouts off. Any other value is the time in milliseconds granted
- * to each <tt>EventHandler</tt> before it gets blacklisted.
- * </p>
- * <p>
- * <p>
- * <tt>org.apache.felix.eventadmin.RequireTopic</tt> - Are <tt>EventHandler</tt>
- * required to be registered with a topic?
- * </p>
- * The default is <tt>true</tt>. The specification says that <tt>EventHandler</tt>
- * must register with a list of topics they are interested in. Setting this value to
- * <tt>false</tt> will enable that handlers without a topic are receiving all events
- * (i.e., they are treated the same as with a topic=*).
- * </p>
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
@@ -85,19 +39,7 @@
// Two places are affected by this namely, security/* and handler/*
public class Activator implements BundleActivator
{
- // The thread pool used - this is a member because we need to close it on stop
- private volatile ThreadPool m_sync_pool;
-
- private volatile ThreadPool m_async_pool;
-
- // The actual implementation of the service - this is a member because we need to
- // close it on stop. Note, security is not part of this implementation but is
- // added via a decorator in the start method (this is the wrapped object without
- // the wrapper).
- private volatile EventAdminImpl m_admin;
-
- // The registration of the security decorator factory (i.e., the service)
- private volatile ServiceRegistration m_registration;
+ private volatile Configuration m_config;
/**
* Called upon starting of the bundle. Constructs and registers the EventAdmin
@@ -119,93 +61,9 @@
// independent of the org.osgi.service.log package)
LogWrapper.setContext(context);
- // 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.
- final int cacheSize = getIntProperty("org.apache.felix.eventadmin.CacheSize",
- context, 30, 10);
+ m_config = new Configuration(context);
- // 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.
- // A value of less then 2 triggers the default value. A value of 2
- // effectively disables thread pooling. Furthermore, this will be used by
- // a lazy thread pool (i.e., new threads are created when needed). Ones the
- // the size is reached and no cached thread is available new threads will
- // be created.
- final int threadPoolSize = getIntProperty(
- "org.apache.felix.eventadmin.ThreadPoolSize", context, 20, 2);
-
- // The timeout in milliseconds - A value of less then 100 turns timeouts off.
- // Any other value is the time in milliseconds granted to each EventHandler
- // before it gets blacklisted.
- final int timeout = getIntProperty("org.apache.felix.eventadmin.Timeout",
- context, 5000, Integer.MIN_VALUE);
-
- // Are EventHandler required to be registered with a topic? - The default is
- // true. The specification says that EventHandler must register with a list
- // of topics they are interested in. Setting this value to false will enable
- // that handlers without a topic are receiving all events
- // (i.e., they are treated the same as with a topic=*).
- final boolean requireTopic = getBooleanProperty(
- "org.apache.felix.eventadmin.RequireTopic", context, true);
-
- LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
- "org.apache.felix.eventadmin.CacheSize=" + cacheSize);
-
- LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
- "org.apache.felix.eventadmin.ThreadPoolSize=" + threadPoolSize);
-
- LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
- "org.apache.felix.eventadmin.Timeout=" + timeout);
-
- LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
- "org.apache.felix.eventadmin.RequireTopic=" + requireTopic);
-
- final TopicPermissions publishPermissions = new CacheTopicPermissions(
- new LeastRecentlyUsedCacheMap(cacheSize), TopicPermission.PUBLISH);
-
- final TopicPermissions subscribePermissions = new CacheTopicPermissions(
- new LeastRecentlyUsedCacheMap(cacheSize), TopicPermission.SUBSCRIBE);
-
- final TopicHandlerFilters topicHandlerFilters =
- new CacheTopicHandlerFilters(new LeastRecentlyUsedCacheMap(cacheSize),
- requireTopic);
-
- final Filters filters = new CacheFilters(
- new LeastRecentlyUsedCacheMap(cacheSize), context);
-
- // 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(context,
- new CleanBlackList(), topicHandlerFilters, filters,
- subscribePermissions);
-
- // 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
- // caching of threads.
- m_sync_pool = new DefaultThreadPool(threadPoolSize, true);
- m_async_pool = new DefaultThreadPool(threadPoolSize > 5 ? threadPoolSize / 2 : 2, false);
-
- final DeliverTask syncExecuter = createSyncExecuters( m_sync_pool, timeout);
- m_admin = createEventAdmin(context,
- handlerTasks,
- createAsyncExecuters(m_async_pool, syncExecuter),
- syncExecuter);
-
- // register the admin wrapped in a service factory (SecureEventAdminFactory)
- // that hands-out the m_admin object wrapped in a decorator that checks
- // appropriated permissions of each calling bundle
- m_registration = context.registerService(EventAdmin.class.getName(),
- new SecureEventAdminFactory(m_admin, publishPermissions), null);
-
- // Finally, adapt the outside events to our kind of events as per spec
- adaptEvents(context, m_admin);
+ m_config.start();
}
/**
@@ -221,141 +79,10 @@
*/
public void stop(final BundleContext context)
{
- // We need to unregister manually
- m_registration.unregister();
-
- m_admin.stop();
-
- m_admin = null;
-
- m_registration = null;
-
- m_async_pool.close();
-
- m_sync_pool.close();
-
- m_async_pool = null;
-
- m_sync_pool = null;
- }
-
-
- /**
- * Create a event admin implementation.
- * @param context The bundle context
- * @param handlerTasks
- * @param asyncExecuters
- * @param syncExecuters
- * @return
- */
- protected EventAdminImpl createEventAdmin(BundleContext context,
- HandlerTasks handlerTasks,
- DeliverTask asyncExecuters,
- DeliverTask syncExecuters)
- {
- return new EventAdminImpl(handlerTasks, asyncExecuters, syncExecuters);
- }
-
- /*
- * Create an AsyncDeliverTasks object that is used to dispatch asynchronous
- * events. Additionally, the asynchronous dispatch queue is initialized and
- * activated (i.e., a thread is started via the given ThreadPool).
- */
- private DeliverTask createAsyncExecuters(final ThreadPool pool, final DeliverTask deliverTask)
- {
- // init the queue
- final AsyncDeliverTasks result = new AsyncDeliverTasks(pool, deliverTask);
-
- return result;
- }
-
- /*
- * Create a SyncDeliverTasks object that is used to dispatch synchronous events.
- * Additionally, the synchronous dispatch queue is initialized and activated
- * (i.e., a thread is started via the given ThreadPool).
- */
- private DeliverTask createSyncExecuters(final ThreadPool pool, final long timeout)
- {
- // init the queue
- final SyncDeliverTasks result = new SyncDeliverTasks(pool, (timeout > 100 ? timeout : 0));
-
- return result;
- }
-
- /*
- * Init the adapters in org.apache.felix.eventadmin.impl.adapter
- */
- private void adaptEvents(final BundleContext context, final EventAdmin admin)
- {
- new FrameworkEventAdapter(context, admin);
-
- new BundleEventAdapter(context, admin);
-
- new ServiceEventAdapter(context, admin);
-
- new LogEventAdapter(context, admin);
- }
-
- /*
- * Returns either the parsed int from the value of the property if it is set and
- * not less then the min value or the default. Additionally, a warning is
- * generated in case the value is erroneous (i.e., can not be parsed as an int or
- * is less then the min value).
- */
- private int getIntProperty(final String key, final BundleContext context,
- final int defaultValue, final int min)
- {
- final String value = context.getProperty(key);
-
- if(null != value)
+ if ( m_config != null )
{
- try {
- final int result = Integer.parseInt(value);
-
- if(result >= min)
- {
- return result;
- }
-
- LogWrapper.getLogger().log(LogWrapper.LOG_WARNING,
- "Value for property: " + key + " is to low - Using default");
- } catch (NumberFormatException e) {
- LogWrapper.getLogger().log(LogWrapper.LOG_WARNING,
- "Unable to parse property: " + key + " - Using default", e);
- }
+ m_config.destroy();
}
-
- return defaultValue;
- }
-
-
- /*
- * Returns true if the value of the property is set and is either 1, true, or yes
- * Returns false if the value of the property is set and is either 0, false, or no
- * Returns the defaultValue otherwise
- */
- private boolean getBooleanProperty(final String key, final BundleContext context,
- final boolean defaultValue)
- {
- String value = context.getProperty(key);
-
- if(null != value)
- {
- value = value.trim().toLowerCase();
-
- if(0 < value.length() && ("0".equals(value) || "false".equals(value)
- || "no".equals(value)))
- {
- return false;
- }
-
- if(0 < value.length() && ("1".equals(value) || "true".equals(value)
- || "yes".equals(value)))
- {
- return true;
- }
- }
-
- return defaultValue;
+ m_config = null;
}
}
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
new file mode 100644
index 0000000..0f2224b
--- /dev/null
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java
@@ -0,0 +1,569 @@
+/*
+ * 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.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.eventadmin.impl.adapter.AbstractAdapter;
+import org.apache.felix.eventadmin.impl.adapter.BundleEventAdapter;
+import org.apache.felix.eventadmin.impl.adapter.FrameworkEventAdapter;
+import org.apache.felix.eventadmin.impl.adapter.LogEventAdapter;
+import org.apache.felix.eventadmin.impl.adapter.ServiceEventAdapter;
+import org.apache.felix.eventadmin.impl.dispatch.DefaultThreadPool;
+import org.apache.felix.eventadmin.impl.dispatch.ThreadPool;
+import org.apache.felix.eventadmin.impl.handler.BlacklistingHandlerTasks;
+import org.apache.felix.eventadmin.impl.handler.CacheFilters;
+import org.apache.felix.eventadmin.impl.handler.CacheTopicHandlerFilters;
+import org.apache.felix.eventadmin.impl.handler.CleanBlackList;
+import org.apache.felix.eventadmin.impl.handler.Filters;
+import org.apache.felix.eventadmin.impl.handler.HandlerTasks;
+import org.apache.felix.eventadmin.impl.handler.TopicHandlerFilters;
+import org.apache.felix.eventadmin.impl.security.CacheTopicPermissions;
+import org.apache.felix.eventadmin.impl.security.SecureEventAdminFactory;
+import org.apache.felix.eventadmin.impl.security.TopicPermissions;
+import org.apache.felix.eventadmin.impl.tasks.AsyncDeliverTasks;
+import org.apache.felix.eventadmin.impl.tasks.DeliverTask;
+import org.apache.felix.eventadmin.impl.tasks.SyncDeliverTasks;
+import org.apache.felix.eventadmin.impl.util.LeastRecentlyUsedCacheMap;
+import org.apache.felix.eventadmin.impl.util.LogWrapper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.event.TopicPermission;
+import org.osgi.service.metatype.MetaTypeProvider;
+
+
+/**
+ * The <code>Configuration</code> class encapsules the
+ * configuration for the event admin.
+ *
+ * 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>
+ * The default value is 10. Increase in case of a large amount of synchronous events
+ * where the <tt>EventHandler</tt> services in turn send new synchronous events in
+ * the event dispatching thread or a lot of timeouts are to be expected. A value of
+ * less then 2 triggers the default value. A value of 2 effectively disables thread
+ * pooling.
+ * </p>
+ * <p>
+ * <p>
+ * <tt>org.apache.felix.eventadmin.Timeout</tt> - The black-listing timeout in
+ * milliseconds
+ * </p>
+ * The default value is 5000. Increase or decrease at own discretion. A value of less
+ * then 100 turns timeouts off. Any other value is the time in milliseconds granted
+ * to each <tt>EventHandler</tt> before it gets blacklisted.
+ * </p>
+ * <p>
+ * <p>
+ * <tt>org.apache.felix.eventadmin.RequireTopic</tt> - Are <tt>EventHandler</tt>
+ * required to be registered with a topic?
+ * </p>
+ * The default is <tt>true</tt>. The specification says that <tt>EventHandler</tt>
+ * must register with a list of topics they are interested in. Setting this value to
+ * <tt>false</tt> will enable that handlers without a topic are receiving all events
+ * (i.e., they are treated the same as with a topic=*).
+ * </p>
+ *
+ * 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.
+ */
+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";
+
+ /** The bundle context. */
+ private final BundleContext bundleContext;
+
+ private int cacheSize;
+
+ private int threadPoolSize;
+
+ private int timeout;
+
+ private boolean requireTopic;
+
+ // The thread pool used - this is a member because we need to close it on stop
+ private volatile ThreadPool m_sync_pool;
+
+ private volatile ThreadPool m_async_pool;
+
+ // The actual implementation of the service - this is a member because we need to
+ // close it on stop. Note, security is not part of this implementation but is
+ // added via a decorator in the start method (this is the wrapped object without
+ // the wrapper).
+ private volatile EventAdminImpl m_admin;
+
+ // The registration of the security decorator factory (i.e., the service)
+ private volatile ServiceRegistration m_registration;
+
+ // all adapters
+ private AbstractAdapter[] adapters;
+
+ public Configuration( BundleContext bundleContext )
+ {
+ this.bundleContext = bundleContext;
+
+ // default configuration
+ configure( null );
+
+ // listen for Configuration Admin configuration
+ try
+ {
+ Object service = new ManagedService()
+ {
+ public void updated( Dictionary properties ) throws ConfigurationException
+ {
+ configure( properties );
+ stop();
+ start();
+ }
+ };
+ // add meta type provider if interfaces are available
+ Object enhancedService = tryToCreateMetaTypeProvider(service);
+ final String[] interfaceNames;
+ if ( enhancedService == null )
+ {
+ interfaceNames = new String[] {ManagedService.class.getName()};
+ }
+ else
+ {
+ interfaceNames = new String[] {ManagedService.class.getName(), MetaTypeProvider.class.getName()};
+ service = enhancedService;
+ }
+ Dictionary props = new Hashtable();
+ props.put( Constants.SERVICE_PID, PID );
+ bundleContext.registerService( interfaceNames, service, props );
+ }
+ catch ( Throwable t )
+ {
+ // don't care
+ }
+ }
+
+ /**
+ * Configures this instance.
+ */
+ void configure( Dictionary config )
+ {
+ 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.
+ cacheSize = getIntProperty(PROP_CACHE_SIZE,
+ this.bundleContext, 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.
+ // A value of less then 2 triggers the default value. A value of 2
+ // effectively disables thread pooling. Furthermore, this will be used by
+ // a lazy thread pool (i.e., new threads are created when needed). Ones the
+ // the size is reached and no cached thread is available new threads will
+ // be created.
+ threadPoolSize = getIntProperty(
+ PROP_THREAD_POOL_SIZE, this.bundleContext, 20, 2);
+
+ // The timeout in milliseconds - A value of less then 100 turns timeouts off.
+ // Any other value is the time in milliseconds granted to each EventHandler
+ // before it gets blacklisted.
+ timeout = getIntProperty(PROP_TIMEOUT,
+ this.bundleContext, 5000, Integer.MIN_VALUE);
+
+ // Are EventHandler required to be registered with a topic? - The default is
+ // true. The specification says that EventHandler must register with a list
+ // of topics they are interested in. Setting this value to false will enable
+ // that handlers without a topic are receiving all events
+ // (i.e., they are treated the same as with a topic=*).
+ requireTopic = getBooleanProperty(
+ PROP_REQUIRE_TOPIC, this.bundleContext, true);
+ }
+ else
+ {
+ cacheSize = getIntProperty(PROP_CACHE_SIZE, config, 30, 10);
+ threadPoolSize = getIntProperty(PROP_THREAD_POOL_SIZE, config, 20, 2);
+ timeout = getIntProperty(PROP_TIMEOUT, config, 5000, Integer.MIN_VALUE);
+ requireTopic = getBooleanProperty(PROP_REQUIRE_TOPIC, config, true);
+ }
+ }
+
+ public synchronized void start()
+ {
+ LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
+ PROP_CACHE_SIZE + "=" + cacheSize);
+ LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
+ PROP_THREAD_POOL_SIZE + "=" + threadPoolSize);
+ LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
+ PROP_TIMEOUT + "=" + timeout);
+ LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
+ PROP_REQUIRE_TOPIC + "=" + requireTopic);
+
+ final TopicPermissions publishPermissions = new CacheTopicPermissions(
+ new LeastRecentlyUsedCacheMap(cacheSize), TopicPermission.PUBLISH);
+
+ final TopicPermissions subscribePermissions = new CacheTopicPermissions(
+ new LeastRecentlyUsedCacheMap(cacheSize), TopicPermission.SUBSCRIBE);
+
+ final TopicHandlerFilters topicHandlerFilters =
+ new CacheTopicHandlerFilters(new LeastRecentlyUsedCacheMap(cacheSize),
+ requireTopic);
+
+ final Filters filters = new CacheFilters(
+ new LeastRecentlyUsedCacheMap(cacheSize), this.bundleContext);
+
+ // 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(this.bundleContext,
+ new CleanBlackList(), topicHandlerFilters, filters,
+ subscribePermissions);
+
+ // 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
+ // caching of threads.
+ m_sync_pool = new DefaultThreadPool(threadPoolSize, true);
+ m_async_pool = new DefaultThreadPool(threadPoolSize > 5 ? threadPoolSize / 2 : 2, false);
+
+ final DeliverTask syncExecuter = createSyncExecuters( m_sync_pool, timeout);
+ m_admin = createEventAdmin(this.bundleContext,
+ handlerTasks,
+ createAsyncExecuters(m_async_pool, syncExecuter),
+ syncExecuter);
+
+ // register the admin wrapped in a service factory (SecureEventAdminFactory)
+ // that hands-out the m_admin object wrapped in a decorator that checks
+ // appropriated permissions of each calling bundle
+ m_registration = this.bundleContext.registerService(EventAdmin.class.getName(),
+ new SecureEventAdminFactory(m_admin, publishPermissions), null);
+
+ // Finally, adapt the outside events to our kind of events as per spec
+ adaptEvents(this.bundleContext, m_admin);
+ }
+
+ /**
+ * Called to stop the event admin and restart it.
+ */
+ public synchronized void stop()
+ {
+ // We need to unregister manually
+ if ( m_registration != null )
+ {
+ m_registration.unregister();
+ m_registration = null;
+ }
+ if ( m_admin != null )
+ {
+ m_admin.stop();
+ m_admin = null;
+ }
+ if ( m_async_pool != null )
+ {
+ m_async_pool.close();
+ m_async_pool = null;
+ }
+ if ( m_sync_pool != null )
+ {
+ m_sync_pool.close();
+ m_sync_pool = null;
+ }
+ }
+
+ /**
+ * Called upon stopping the bundle. This will block until all pending events are
+ * delivered. An IllegalStateException will be thrown on new events starting with
+ * the begin of this method. However, it might take some time until we settle
+ * down which is somewhat cumbersome given that the spec asks for return in
+ * a timely manner.
+ */
+ public synchronized void destroy()
+ {
+ if ( this.adapters != null )
+ {
+ for(int i=0;i<adapters.length;i++)
+ {
+ adapters[i].destroy(bundleContext);
+ }
+ adapters = null;
+ }
+ }
+
+ /**
+ * Create a event admin implementation.
+ * @param context The bundle context
+ * @param handlerTasks
+ * @param asyncExecuters
+ * @param syncExecuters
+ * @return
+ */
+ protected EventAdminImpl createEventAdmin(BundleContext context,
+ HandlerTasks handlerTasks,
+ DeliverTask asyncExecuters,
+ DeliverTask syncExecuters)
+ {
+ return new EventAdminImpl(handlerTasks, asyncExecuters, syncExecuters);
+ }
+
+ /*
+ * Create an AsyncDeliverTasks object that is used to dispatch asynchronous
+ * events. Additionally, the asynchronous dispatch queue is initialized and
+ * activated (i.e., a thread is started via the given ThreadPool).
+ */
+ private DeliverTask createAsyncExecuters(final ThreadPool pool, final DeliverTask deliverTask)
+ {
+ // init the queue
+ final AsyncDeliverTasks result = new AsyncDeliverTasks(pool, deliverTask);
+
+ return result;
+ }
+
+ /*
+ * Create a SyncDeliverTasks object that is used to dispatch synchronous events.
+ * Additionally, the synchronous dispatch queue is initialized and activated
+ * (i.e., a thread is started via the given ThreadPool).
+ */
+ private DeliverTask createSyncExecuters(final ThreadPool pool, final long timeout)
+ {
+ // init the queue
+ final SyncDeliverTasks result = new SyncDeliverTasks(pool, (timeout > 100 ? timeout : 0));
+
+ return result;
+ }
+
+ /*
+ * Init the adapters in org.apache.felix.eventadmin.impl.adapter
+ */
+ private void adaptEvents(final BundleContext context, final EventAdmin admin)
+ {
+ if ( adapters == null )
+ {
+ adapters = new AbstractAdapter[4];
+ adapters[0] = new FrameworkEventAdapter(context, admin);
+ adapters[1] = new BundleEventAdapter(context, admin);
+ adapters[2] = new ServiceEventAdapter(context, admin);
+ adapters[3] = new LogEventAdapter(context, admin);
+ }
+ else
+ {
+ for(int i=0; i<adapters.length; i++)
+ {
+ adapters[i].update(admin);
+ }
+ }
+ }
+
+ public int getCacheSize()
+ {
+ return cacheSize;
+ }
+
+ public int getThreadPoolSize()
+ {
+ return threadPoolSize;
+ }
+
+ public int getTimeout()
+ {
+ return timeout;
+ }
+
+ public boolean getRequireTopic()
+ {
+ return requireTopic;
+ }
+
+ private Object tryToCreateMetaTypeProvider(final Object managedService)
+ {
+ try
+ {
+ return new MetaTypeProviderImpl(this, (ManagedService)managedService);
+ } catch (Throwable t)
+ {
+ // we simply ignore this
+ }
+ return null;
+ }
+
+ /**
+ * Returns either the parsed int from the value of the property if it is set and
+ * not less then the min value or the default. Additionally, a warning is
+ * generated in case the value is erroneous (i.e., can not be parsed as an int or
+ * is less then the min value).
+ */
+ private int getIntProperty(final String key, final BundleContext context,
+ final int defaultValue, final int min)
+ {
+ final String value = context.getProperty(key);
+
+ if(null != value)
+ {
+ try {
+ final int result = Integer.parseInt(value);
+
+ if(result >= min)
+ {
+ return result;
+ }
+
+ LogWrapper.getLogger().log(LogWrapper.LOG_WARNING,
+ "Value for property: " + key + " is to low - Using default");
+ } catch (NumberFormatException e) {
+ LogWrapper.getLogger().log(LogWrapper.LOG_WARNING,
+ "Unable to parse property: " + key + " - Using default", e);
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns either the parsed int from the value of the property if it is set and
+ * not less then the min value or the default. Additionally, a warning is
+ * generated in case the value is erroneous (i.e., can not be parsed as an int or
+ * is less then the min value).
+ */
+ private int getIntProperty(final String key, final Dictionary dict,
+ final int defaultValue, final int min)
+ {
+ final Object value = dict.get(key);
+
+ if(null != value)
+ {
+ final int result;
+ if ( value instanceof Integer )
+ {
+ result = ((Integer)value).intValue();
+ }
+ else
+ {
+ try
+ {
+ result = Integer.parseInt(value.toString());
+ }
+ catch (NumberFormatException e)
+ {
+ LogWrapper.getLogger().log(LogWrapper.LOG_WARNING,
+ "Unable to parse property: " + key + " - Using default", e);
+ return defaultValue;
+ }
+ }
+ if(result >= min)
+ {
+ return result;
+ }
+
+ LogWrapper.getLogger().log(LogWrapper.LOG_WARNING,
+ "Value for property: " + key + " is to low - Using default");
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns true if the value of the property is set and is either 1, true, or yes
+ * Returns false if the value of the property is set and is either 0, false, or no
+ * Returns the defaultValue otherwise
+ */
+ private boolean getBooleanProperty(final String key, final BundleContext context,
+ final boolean defaultValue)
+ {
+ String value = context.getProperty(key);
+
+ if(null != value)
+ {
+ value = value.trim().toLowerCase();
+
+ if(0 < value.length() && ("0".equals(value) || "false".equals(value)
+ || "no".equals(value)))
+ {
+ return false;
+ }
+
+ if(0 < value.length() && ("1".equals(value) || "true".equals(value)
+ || "yes".equals(value)))
+ {
+ return true;
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns true if the value of the property is set and is either 1, true, or yes
+ * Returns false if the value of the property is set and is either 0, false, or no
+ * Returns the defaultValue otherwise
+ */
+ private boolean getBooleanProperty(final String key, final Dictionary dict,
+ final boolean defaultValue)
+ {
+ Object obj = dict.get(key);
+
+ if(null != obj)
+ {
+ if ( obj instanceof Boolean )
+ {
+ return ((Boolean)obj).booleanValue();
+ }
+ String value = obj.toString().trim().toLowerCase();
+
+ if(0 < value.length() && ("0".equals(value) || "false".equals(value)
+ || "no".equals(value)))
+ {
+ return false;
+ }
+
+ if(0 < value.length() && ("1".equals(value) || "true".equals(value)
+ || "yes".equals(value)))
+ {
+ return true;
+ }
+ }
+
+ return defaultValue;
+ }
+}
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
new file mode 100644
index 0000000..cb5e88f
--- /dev/null
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/MetaTypeProviderImpl.java
@@ -0,0 +1,242 @@
+/*
+ * 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.io.InputStream;
+import java.util.ArrayList;
+import java.util.Dictionary;
+
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.metatype.*;
+
+/**
+ * The optional meta type provider for the event admin config.
+ */
+public class MetaTypeProviderImpl
+ implements MetaTypeProvider, ManagedService
+{
+ private final int cacheSize;
+ private final int threadPoolSize;
+ private final int timeout;
+ private final boolean requireTopic;
+
+ private final ManagedService delegatee;
+
+ public MetaTypeProviderImpl(final Configuration config,
+ final ManagedService delegatee)
+ {
+ this.cacheSize = config.getCacheSize();
+ this.threadPoolSize = config.getThreadPoolSize();
+ this.timeout = config.getTimeout();
+ this.requireTopic = config.getRequireTopic();
+ this.delegatee = delegatee;
+ }
+
+ private ObjectClassDefinition ocd;
+
+ public void updated(Dictionary properties) throws ConfigurationException
+ {
+ this.delegatee.updated(properties);
+ }
+
+ /**
+ * @see org.osgi.service.metatype.MetaTypeProvider#getLocales()
+ */
+ public String[] getLocales()
+ {
+ return null;
+ }
+
+ /**
+ * @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String, java.lang.String)
+ */
+ public ObjectClassDefinition getObjectClassDefinition( String id, String locale )
+ {
+ if ( !Configuration.PID.equals( id ) )
+ {
+ return null;
+ }
+
+ if ( ocd == null )
+ {
+ 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.", this.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 " +
+ "the event dispatching thread or a lot of timeouts are to be expected. A value of " +
+ "less then 2 triggers the default value. A value of 2 effectively disables thread pooling.",
+ this.threadPoolSize ) );
+
+ adList.add( new AttributeDefinitionImpl( Configuration.PROP_TIMEOUT, "Timeout",
+ "The black-listing timeout in milliseconds. The default value is 5000. Increase or decrease " +
+ "at own discretion. A value of less then 100 turns timeouts off. Any other value is the time " +
+ "in milliseconds granted to each event handler before it gets blacklisted",
+ this.timeout ) );
+
+ adList.add( new AttributeDefinitionImpl( Configuration.PROP_REQUIRE_TOPIC, "Require Topic",
+ "Are event handlers required to be registered with a topic? " +
+ "This is enabled by default. The specification says that event handlers " +
+ "must register with a list of topics they are interested in. Disabling this setting " +
+ "will enable that handlers without a topic are receiving all events " +
+ "(i.e., they are treated the same as with a topic=*).",
+ this.requireTopic ) );
+
+ ocd = new ObjectClassDefinition()
+ {
+
+ private final AttributeDefinition[] attrs = ( AttributeDefinition[] ) adList
+ .toArray( new AttributeDefinition[adList.size()] );
+
+
+ public String getName()
+ {
+ return "Apache Felix Event Admin Implementation";
+ }
+
+
+ public InputStream getIcon( int arg0 )
+ {
+ return null;
+ }
+
+
+ public String getID()
+ {
+ return Configuration.PID;
+ }
+
+
+ public String getDescription()
+ {
+ return "Configuration for the Apache Felix Event Admin Implementation." +
+ " This configuration overwrites configuration defined in framework properties of the same names.";
+ }
+
+
+ public AttributeDefinition[] getAttributeDefinitions( int filter )
+ {
+ return ( filter == OPTIONAL ) ? null : attrs;
+ }
+ };
+ }
+
+ return ocd;
+ }
+
+ class AttributeDefinitionImpl implements AttributeDefinition
+ {
+
+ private final String id;
+ private final String name;
+ private final String description;
+ private final int type;
+ private final String[] defaultValues;
+ private final int cardinality;
+ private final String[] optionLabels;
+ private final String[] optionValues;
+
+
+ AttributeDefinitionImpl( final String id, final String name, final String description, final boolean defaultValue )
+ {
+ this( id, name, description, BOOLEAN, new String[]
+ { String.valueOf(defaultValue) }, 0, null, null );
+ }
+
+ AttributeDefinitionImpl( final String id, final String name, final String description, final int defaultValue )
+ {
+ this( id, name, description, INTEGER, new String[]
+ { String.valueOf(defaultValue) }, 0, null, null );
+ }
+
+ AttributeDefinitionImpl( final String id, final String name, final String description, final int type,
+ final String[] defaultValues, final int cardinality, final String[] optionLabels,
+ final String[] optionValues )
+ {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ this.type = type;
+ this.defaultValues = defaultValues;
+ this.cardinality = cardinality;
+ this.optionLabels = optionLabels;
+ this.optionValues = optionValues;
+ }
+
+
+ public int getCardinality()
+ {
+ return cardinality;
+ }
+
+
+ public String[] getDefaultValue()
+ {
+ return defaultValues;
+ }
+
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+
+ public String getID()
+ {
+ return id;
+ }
+
+
+ public String getName()
+ {
+ return name;
+ }
+
+
+ public String[] getOptionLabels()
+ {
+ return optionLabels;
+ }
+
+
+ public String[] getOptionValues()
+ {
+ return optionValues;
+ }
+
+
+ public int getType()
+ {
+ return type;
+ }
+
+
+ public String validate( String arg0 )
+ {
+ return null;
+ }
+ }
+}
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
new file mode 100644
index 0000000..1d519eb
--- /dev/null
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.adapter;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * 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
+{
+ private volatile EventAdmin m_admin;
+
+ /**
+ * The constructor of the adapter.
+ *
+ * @param admin The <tt>EventAdmin</tt> to use for posting events.
+ */
+ public AbstractAdapter(final EventAdmin admin)
+ {
+ update(admin);
+ }
+
+ public void update(final EventAdmin admin)
+ {
+ if (null == admin)
+ {
+ throw new NullPointerException("EventAdmin must not be null");
+ }
+
+ m_admin = admin;
+ }
+
+ protected EventAdmin getEventAdmin()
+ {
+ return m_admin;
+ }
+
+ public abstract void destroy(final BundleContext bundleContext);
+}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/BundleEventAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/BundleEventAdapter.java
index 6d80fb0..c636e06 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/BundleEventAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/BundleEventAdapter.java
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -31,37 +31,33 @@
/**
* This class registers itself as a listener for bundle events and posts them via
* the EventAdmin as specified in 113.6.4 OSGi R4 compendium.
- *
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
-public class BundleEventAdapter implements BundleListener
+public class BundleEventAdapter extends AbstractAdapter implements BundleListener
{
- private final EventAdmin m_admin;
-
/**
* The constructor of the adapter. This will register the adapter with the given
- * context as a <tt>BundleListener</tt> and subsequently, will post received
+ * context as a <tt>BundleListener</tt> and subsequently, will post received
* events via the given EventAdmin.
- *
+ *
* @param context The bundle context with which to register as a listener.
* @param admin The <tt>EventAdmin</tt> to use for posting events.
*/
public BundleEventAdapter(final BundleContext context, final EventAdmin admin)
{
- if(null == admin)
- {
- throw new NullPointerException("EventAdmin must not be null");
- }
-
- m_admin = admin;
-
+ super(admin);
context.addBundleListener(this);
}
-
+
+ public void destroy(BundleContext context) {
+ context.removeBundleListener(this);
+ }
+
/**
* Once a bundle event is received this method assembles and posts an event via
- * the <tt>EventAdmin</tt> as specified in 113.6.4 OSGi R4 compendium.
- *
+ * the <tt>EventAdmin</tt> as specified in 113.6.4 OSGi R4 compendium.
+ *
* @param event The event to adapt.
*/
public void bundleChanged(final BundleEvent event)
@@ -114,8 +110,8 @@
}
try {
- m_admin.postEvent(new Event(topic.toString(), properties));
- } catch (IllegalStateException e) {
+ getEventAdmin().postEvent(new Event(topic.toString(), properties));
+ } catch (IllegalStateException e) {
// This is o.k. - indicates that we are stopped.
}
}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/FrameworkEventAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/FrameworkEventAdapter.java
index c7ad2fc..90d8da5 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/FrameworkEventAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/FrameworkEventAdapter.java
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -32,37 +32,34 @@
/**
* This class registers itself as a listener for framework events and posts them via
* the EventAdmin as specified in 113.6.3 OSGi R4 compendium.
- *
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
-public class FrameworkEventAdapter implements FrameworkListener
+public class FrameworkEventAdapter extends AbstractAdapter implements FrameworkListener
{
- private final EventAdmin m_admin;
-
/**
* The constructor of the adapter. This will register the adapter with the
* given context as a <tt>FrameworkListener</tt> and subsequently, will
* post received events via the given EventAdmin.
- *
+ *
* @param context The bundle context with which to register as a listener.
* @param admin The <tt>EventAdmin</tt> to use for posting events.
*/
public FrameworkEventAdapter(final BundleContext context, final EventAdmin admin)
{
- if(null == admin)
- {
- throw new NullPointerException("EventAdmin must not be null");
- }
-
- m_admin = admin;
-
+ super(admin);
+
context.addFrameworkListener(this);
}
-
+
+ public void destroy(BundleContext context) {
+ context.removeFrameworkListener(this);
+ }
+
/**
- * Once a framework event is received this method assembles and posts an event
- * via the <tt>EventAdmin</tt> as specified in 113.6.3 OSGi R4 compendium.
- *
+ * Once a framework event is received this method assembles and posts an event
+ * via the <tt>EventAdmin</tt> as specified in 113.6.3 OSGi R4 compendium.
+ *
* @param event The event to adapt.
*/
public void frameworkEvent(final FrameworkEvent event)
@@ -92,7 +89,7 @@
if (null != thrown)
{
- properties.put(EventConstants.EXCEPTION_CLASS,
+ properties.put(EventConstants.EXCEPTION_CLASS,
thrown.getClass().getName());
final String message = thrown.getMessage();
@@ -135,7 +132,7 @@
}
try {
- m_admin.postEvent(new Event(topic.toString(), properties));
+ getEventAdmin().postEvent(new Event(topic.toString(), properties));
} catch(IllegalStateException e) {
// This is o.k. - indicates that we are stopped.
}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/LogEventAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/LogEventAdapter.java
index 09918f8..1c48586 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/LogEventAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/LogEventAdapter.java
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -36,47 +36,39 @@
/**
* This class registers itself as a listener for <tt>LogReaderService</tt> services
* with the framework and subsequently, a <tt>LogListener</tt> callback with any
- * currently available <tt>LogReaderService</tt>. Any received log event is then
+ * currently available <tt>LogReaderService</tt>. Any received log event is then
* posted via the EventAdmin as specified in 113.6.6 OSGi R4 compendium.
* Note that this class does not create a hard dependency on the org.osgi.service.log
- * packages. The adaption only takes place if it is present or once it becomes
- * available hence, combined with a DynamicImport-Package no hard dependency is
- * needed.
- *
+ * packages. The adaption only takes place if it is present or once it becomes
+ * available hence, combined with a DynamicImport-Package no hard dependency is
+ * needed.
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
-public class LogEventAdapter implements ServiceListener
+public class LogEventAdapter extends AbstractAdapter implements ServiceListener
{
// The internal lock for this object used instead synchronized(this)
private final Object m_lock = new Object();
-
+
private BundleContext m_context;
-
+
// A singleton instance of the used log listener that is the adapter
private Object m_logListener;
-
- final EventAdmin m_admin;
-
+
/**
* The constructor of the adapter. This will register the adapter with the
- * given context as a listener for <tt>LogReaderService</tt> services and
+ * given context as a listener for <tt>LogReaderService</tt> services and
* subsequently, a <tt>LogListener</tt> callback with any currently available
- * <tt>LogReaderService</tt>. Any received log event is then posted via the given
+ * <tt>LogReaderService</tt>. Any received log event is then posted via the given
* EventAdmin.
- *
+ *
* @param context The bundle context with which to register as a listener.
* @param admin The <tt>EventAdmin</tt> to use for posting events.
*/
public LogEventAdapter(final BundleContext context, final EventAdmin admin)
{
- if(null == admin)
- {
- throw new NullPointerException("EventAdmin must not be null");
- }
-
+ super(admin);
m_context = context;
-
- m_admin = admin;
try
{
@@ -92,13 +84,13 @@
{
for (int i = 0; i < refs.length; i++)
{
- final org.osgi.service.log.LogReaderService logReader =
+ final org.osgi.service.log.LogReaderService logReader =
(org.osgi.service.log.LogReaderService) m_context
.getService(refs[i]);
if (null != logReader)
{
- logReader.addLogListener((org.osgi.service.log.LogListener)
+ logReader.addLogListener((org.osgi.service.log.LogListener)
getLogListener());
}
}
@@ -109,32 +101,36 @@
}
}
+ public void destroy(BundleContext context) {
+ context.removeServiceListener(this);
+ }
+
/**
* Once a <tt>LogReaderService</tt> register event is received this method
- * registers a <tt>LogListener</tt> with the received service that assembles
- * and posts any log event via the <tt>EventAdmin</tt> as specified in
- * 113.6.6 OSGi R4 compendium.
- *
+ * registers a <tt>LogListener</tt> with the received service that assembles
+ * and posts any log event via the <tt>EventAdmin</tt> as specified in
+ * 113.6.6 OSGi R4 compendium.
+ *
* @param event The event to adapt.
*/
public void serviceChanged(final ServiceEvent event)
{
if (ServiceEvent.REGISTERED == event.getType())
{
- final org.osgi.service.log.LogReaderService logReader =
+ final org.osgi.service.log.LogReaderService logReader =
(org.osgi.service.log.LogReaderService) m_context
.getService(event.getServiceReference());
if (null != logReader)
{
- logReader.addLogListener((org.osgi.service.log.LogListener)
+ logReader.addLogListener((org.osgi.service.log.LogListener)
getLogListener());
}
}
}
/*
- * Constructs a LogListener that assembles and posts any log event via the
+ * Constructs a LogListener that assembles and posts any log event via the
* EventAdmin as specified in 113.6.6 OSGi R4 compendium. Note that great
* care is taken to not create a hard dependency on the org.osgi.service.log
* package.
@@ -153,9 +149,9 @@
public void logged(final org.osgi.service.log.LogEntry entry)
{
// This is where the assembly as specified in 133.6.6 OSGi R4
- // compendium is taking place (i.e., the log entry is adapted to
+ // compendium is taking place (i.e., the log entry is adapted to
// an event and posted via the EventAdmin)
-
+
final Dictionary properties = new Hashtable();
final Bundle bundle = entry.getBundle();
@@ -224,7 +220,7 @@
// LOG and IGNORE
LogWrapper.getLogger().log(
entry.getServiceReference(),
- LogWrapper.LOG_WARNING, "Exception parsing " +
+ LogWrapper.LOG_WARNING, "Exception parsing " +
EventConstants.SERVICE_ID + "=" + id, ne);
}
}
@@ -234,7 +230,7 @@
if (null != pid)
{
- properties.put(EventConstants.SERVICE_PID,
+ properties.put(EventConstants.SERVICE_PID,
pid.toString());
}
@@ -282,13 +278,13 @@
}
try {
- m_admin.postEvent(new Event(topic.toString(), properties));
+ getEventAdmin().postEvent(new Event(topic.toString(), properties));
} catch(IllegalStateException e) {
// This is o.k. - indicates that we are stopped.
}
}
};
-
+
return m_logListener;
}
}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/ServiceEventAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/ServiceEventAdapter.java
index 4e365a8..7482e13 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/ServiceEventAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/ServiceEventAdapter.java
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -33,32 +33,34 @@
/**
* This class registers itself as a listener for service events and posts them via
* the EventAdmin as specified in 113.6.5 OSGi R4 compendium.
- *
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
-public class ServiceEventAdapter implements ServiceListener
+public class ServiceEventAdapter extends AbstractAdapter implements ServiceListener
{
- private final EventAdmin m_admin;
-
/**
* The constructor of the adapter. This will register the adapter with the
* given context as a <tt>ServiceListener</tt> and subsequently, will
* post received events via the given EventAdmin.
- *
+ *
* @param context The bundle context with which to register as a listener.
* @param admin The <tt>EventAdmin</tt> to use for posting events.
*/
public ServiceEventAdapter(final BundleContext context, final EventAdmin admin)
{
- m_admin = admin;
-
+ super(admin);
+
context.addServiceListener(this);
}
+ public void destroy(BundleContext context) {
+ context.removeServiceListener(this);
+ }
+
/**
- * Once a Service event is received this method assembles and posts an event
- * via the <tt>EventAdmin</tt> as specified in 113.6.5 OSGi R4 compendium.
- *
+ * Once a Service event is received this method assembles and posts an event
+ * via the <tt>EventAdmin</tt> as specified in 113.6.5 OSGi R4 compendium.
+ *
* @param event The event to adapt.
*/
public void serviceChanged(final ServiceEvent event)
@@ -83,7 +85,7 @@
{
// LOG and IGNORE
LogWrapper.getLogger().log(event.getServiceReference(),
- LogWrapper.LOG_WARNING, "Exception parsing " +
+ LogWrapper.LOG_WARNING, "Exception parsing " +
EventConstants.SERVICE_ID + "=" + id, ne);
}
}
@@ -132,7 +134,7 @@
}
try {
- m_admin.postEvent(new Event(topic.toString(), properties));
+ getEventAdmin().postEvent(new Event(topic.toString(), properties));
} catch(IllegalStateException e) {
// This is o.k. - indicates that we are stopped.
}