FELIX-2558 : Handle configuration changes without restarting event admin service
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@991190 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 85d1e6c..839aa80 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
@@ -26,7 +26,6 @@
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.*;
@@ -135,6 +134,9 @@
// the wrapper).
private volatile EventAdminImpl m_admin;
+ // This is the service factory for the event admin with the security impl
+ private volatile SecureEventAdminFactory m_secure_admin;
+
// The registration of the security decorator factory (i.e., the service)
private volatile ServiceRegistration m_registration;
@@ -149,7 +151,7 @@
// default configuration
configure( null );
- start();
+ startOrUpdate();
// check for Configuration Admin configuration
try
@@ -192,27 +194,10 @@
public void run()
{
- final ThreadPool aSyncPool;
- final ThreadPool syncPool;
synchronized ( Configuration.this )
{
- // we will shutdown the pools later
- // to make the downtime as small as possible
- aSyncPool = m_async_pool;
- m_async_pool = null;
- syncPool = m_sync_pool;
- m_sync_pool = null;
- Configuration.this.stop();
Configuration.this.configure( config );
- Configuration.this.start();
- }
- if (aSyncPool != null )
- {
- aSyncPool.close();
- }
- if ( syncPool != null )
- {
- syncPool.close();
+ Configuration.this.startOrUpdate();
}
}
@@ -268,7 +253,8 @@
{
final StringTokenizer st = new StringTokenizer(value, ",");
m_ignoreTimeout = new String[st.countTokens()];
- for(int i=0; i<m_ignoreTimeout.length; i++) {
+ for(int i=0; i<m_ignoreTimeout.length; i++)
+ {
m_ignoreTimeout[i] = st.nextToken();
}
}
@@ -295,9 +281,14 @@
"Value for property: " + PROP_IGNORE_TIMEOUT + " is neither a string nor a string array - Using default");
}
}
+ // a timeout less or equals to 100 means : disable timeout
+ if ( m_timeout <= 100 )
+ {
+ m_timeout = 0;
+ }
}
- private void start()
+ private void startOrUpdate()
{
LogWrapper.getLogger().log(LogWrapper.LOG_DEBUG,
PROP_CACHE_SIZE + "=" + m_cacheSize);
@@ -321,6 +312,28 @@
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
+ // caching of threads.
+ if ( m_sync_pool == null )
+ {
+ m_sync_pool = new DefaultThreadPool(m_threadPoolSize, true);
+ }
+ else
+ {
+ m_sync_pool.configure(m_threadPoolSize);
+ }
+ final int asyncThreadPoolSize = m_threadPoolSize > 5 ? m_threadPoolSize / 2 : 2;
+ if ( m_async_pool == null )
+ {
+ m_async_pool = new DefaultThreadPool(asyncThreadPoolSize, false);
+ }
+ else
+ {
+ 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
@@ -329,57 +342,27 @@
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(m_threadPoolSize, true);
- m_async_pool = new DefaultThreadPool(m_threadPoolSize > 5 ? m_threadPoolSize / 2 : 2, false);
-
- final DeliverTask syncExecuter = new SyncDeliverTasks(m_sync_pool,
- (m_timeout > 100 ? m_timeout : 0),
- m_ignoreTimeout);
- m_admin = createEventAdmin(m_bundleContext,
- handlerTasks,
- new AsyncDeliverTasks(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 = m_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(m_bundleContext, m_admin);
- }
-
- /**
- * Called to stop the event admin.
- */
- private void stop()
- {
- // We need to unregister manually
- if ( m_registration != null )
+ if ( m_admin == null )
{
- m_registration.unregister();
- m_registration = null;
+ m_admin = new EventAdminImpl(handlerTasks, m_sync_pool, m_async_pool, m_timeout, m_ignoreTimeout);
+
+ // Finally, adapt the outside events to our kind of events as per spec
+ adaptEvents(m_admin);
+ // create secure admin factory which is a service factory
+ m_secure_admin = new SecureEventAdminFactory(m_admin, publishPermissions);
+
+ // 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 = m_bundleContext.registerService(EventAdmin.class.getName(),
+ m_secure_admin, null);
}
- if ( m_admin != null )
+ else
{
- m_admin.stop();
- m_admin = null;
+ m_admin.update(handlerTasks, m_timeout, m_ignoreTimeout);
+ m_secure_admin.update(publishPermissions);
}
- 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;
- }
+
}
/**
@@ -406,46 +389,40 @@
m_managedServiceReg.unregister();
m_managedServiceReg = null;
}
- 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;
+ }
}
}
/**
- * 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);
- }
-
- /**
* Init the adapters in org.apache.felix.eventadmin.impl.adapter
*/
- private void adaptEvents(final BundleContext context, final EventAdmin admin)
+ private void adaptEvents(final EventAdmin admin)
{
- if ( m_adapters == null )
- {
- m_adapters = new AbstractAdapter[4];
- m_adapters[0] = new FrameworkEventAdapter(context, admin);
- m_adapters[1] = new BundleEventAdapter(context, admin);
- m_adapters[2] = new ServiceEventAdapter(context, admin);
- m_adapters[3] = new LogEventAdapter(context, admin);
- }
- else
- {
- for(int i=0; i<m_adapters.length; i++)
- {
- m_adapters[i].update(admin);
- }
- }
+ m_adapters = new AbstractAdapter[4];
+ m_adapters[0] = new FrameworkEventAdapter(m_bundleContext, admin);
+ m_adapters[1] = new BundleEventAdapter(m_bundleContext, admin);
+ m_adapters[2] = new ServiceEventAdapter(m_bundleContext, admin);
+ m_adapters[3] = new LogEventAdapter(m_bundleContext, admin);
}
private Object tryToCreateMetaTypeProvider(final Object managedService)
@@ -468,38 +445,6 @@
* 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 Object value,
final int defaultValue, final int min)
{
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
index 1d46295..887c228 100644
--- 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
@@ -18,9 +18,9 @@
*/
package org.apache.felix.eventadmin.impl;
+import org.apache.felix.eventadmin.impl.dispatch.ThreadPool;
import org.apache.felix.eventadmin.impl.handler.HandlerTasks;
-import org.apache.felix.eventadmin.impl.tasks.DeliverTask;
-import org.apache.felix.eventadmin.impl.tasks.HandlerTask;
+import org.apache.felix.eventadmin.impl.tasks.*;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
@@ -47,7 +47,7 @@
private final DeliverTask m_postManager;
// The synchronous event dispatcher
- private final DeliverTask m_sendManager;
+ private final SyncDeliverTasks m_sendManager;
/**
* The constructor of the <tt>EventAdmin</tt> implementation. The
@@ -56,21 +56,26 @@
* <tt>DeliverTasks</tt> are used to dispatch the event.
*
* @param managers The factory used to determine applicable <tt>EventHandler</tt>
- * @param postManager The asynchronous event dispatcher
- * @param sendManager The synchronous event dispatcher
+ * @param syncPool The synchronous thread pool
+ * @param asyncPool The asynchronous thread pool
*/
public EventAdminImpl(final HandlerTasks managers,
- final DeliverTask postManager, final DeliverTask sendManager)
+ final ThreadPool syncPool,
+ final ThreadPool asyncPool,
+ final int timeout,
+ final String[] ignoreTimeout)
{
checkNull(managers, "Managers");
- checkNull(postManager, "PostManager");
- checkNull(sendManager, "SendManager");
+ checkNull(syncPool, "syncPool");
+ checkNull(asyncPool, "asyncPool");
m_managers = managers;
- m_postManager = postManager;
+ m_sendManager = new SyncDeliverTasks(syncPool,
+ (timeout > 100 ? timeout : 0),
+ ignoreTimeout);
- m_sendManager = sendManager;
+ m_postManager = new AsyncDeliverTasks(asyncPool, m_sendManager);
}
/**
@@ -130,7 +135,17 @@
};
}
- /*
+ /**
+ * 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.
*/
@@ -149,7 +164,7 @@
}
}
- /*
+ /**
* 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".
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 1d519eb..8e5cde2 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
@@ -37,11 +37,6 @@
*/
public AbstractAdapter(final EventAdmin admin)
{
- update(admin);
- }
-
- public void update(final EventAdmin admin)
- {
if (null == admin)
{
throw new NullPointerException("EventAdmin must not be null");
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/dispatch/DefaultThreadPool.java
index f7bcd08..c809e37 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/dispatch/DefaultThreadPool.java
@@ -67,18 +67,26 @@
}
});
}
- super.setMinimumPoolSize(poolSize);
- super.setMaximumPoolSize(poolSize + 10);
- super.setKeepAliveTime(60000);
+ configure(poolSize);
+ setKeepAliveTime(60000);
runWhenBlocked();
}
/**
+ * @see org.apache.felix.eventadmin.impl.dispatch.ThreadPool#configure(int)
+ */
+ public void configure(final int poolSize)
+ {
+ setMinimumPoolSize(poolSize);
+ setMaximumPoolSize(poolSize + 10);
+ }
+
+ /**
* @see org.apache.felix.eventadmin.impl.dispatch.ThreadPool#close()
*/
public void close()
{
- shutdownAfterProcessingCurrentlyQueuedTasks();
+ shutdownNow();
try
{
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/dispatch/ThreadPool.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/dispatch/ThreadPool.java
index 0dfd3e8..d35c050 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/dispatch/ThreadPool.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/dispatch/ThreadPool.java
@@ -39,11 +39,14 @@
*
* @param task The task to execute
*/
- public void executeTask(final Runnable task);
+ void executeTask(final Runnable task);
/**
* Close the pool i.e, stop pooling threads. Note that subsequently, task will
* still be executed but no pooling is taking place anymore.
*/
- public void close();
+ void close();
+
+ /** Configure a new pool size. */
+ void configure(int poolSize);
}
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/SecureEventAdminFactory.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/SecureEventAdminFactory.java
index 5bf18b4..c779d21 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/SecureEventAdminFactory.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/SecureEventAdminFactory.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
@@ -18,44 +18,42 @@
*/
package org.apache.felix.eventadmin.impl.security;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceFactory;
-import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.*;
import org.osgi.service.event.EventAdmin;
/**
* This class is a factory that secures a given <tt>EventAdmin</tt> service by
* wrapping it with a new instance of an <tt>EventAdminSecurityDecorator</tt> on
- * any call to its <tt>getService()</tt> method. The decorator will determine the
- * appropriate permissions by using the given permission factory and the bundle
- * parameter passed to the <tt>getService()</tt> method.
- *
+ * any call to its <tt>getService()</tt> method. The decorator will determine the
+ * appropriate permissions by using the given permission factory and the bundle
+ * parameter passed to the <tt>getService()</tt> method.
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class SecureEventAdminFactory implements ServiceFactory
{
// The EventAdmin to secure
- private EventAdmin m_admin;
-
+ private final EventAdmin m_admin;
+
// The permission factory
- private final TopicPermissions m_topicPermissions;
-
+ private TopicPermissions m_topicPermissions;
+
/**
* The constructor of the factory. The factory will use the given event admin and
* permission factory to create a new <tt>EventAdminSecurityDecorator</tt>
- * on any call to <tt>getService()</tt>.
- *
+ * on any call to <tt>getService()</tt>.
+ *
* @param admin The <tt>EventAdmin</tt> service to secure.
* @param topicPermissions The permission factory to use for permission lookup.
*/
- public SecureEventAdminFactory(final EventAdmin admin, final TopicPermissions
+ public SecureEventAdminFactory(final EventAdmin admin, final TopicPermissions
topicPermissions)
{
checkNull(admin, "Admin");
checkNull(topicPermissions, "TopicPermissions");
-
+
m_admin = admin;
-
+
m_topicPermissions = topicPermissions;
}
@@ -63,12 +61,12 @@
* Returns a new <tt>EventAdminSecurityDecorator</tt> initialized with the
* given <tt>EventAdmin</tt>. That in turn will check any call to post or
* send for the appropriate permissions based on the bundle parameter.
- *
+ *
* @param bundle The bundle used to determine the permissions of the caller
* @param registration The ServiceRegistration that is not used
- *
- * @return The given service instance wrapped by an <tt>EventAdminSecuriryDecorator</tt>
- *
+ *
+ * @return The given service instance wrapped by an <tt>EventAdminSecuriryDecorator</tt>
+ *
* @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle,
* org.osgi.framework.ServiceRegistration)
*/
@@ -81,11 +79,11 @@
/**
* This method doesn't do anything at the moment.
- *
+ *
* @param bundle The bundle object that is not used
* @param registration The ServiceRegistration that is not used
* @param service The service object that is not used
- *
+ *
* @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle,
* org.osgi.framework.ServiceRegistration, java.lang.Object)
*/
@@ -95,7 +93,7 @@
// We don't need to do anything here since we hand-out a new instance with
// any call to getService hence, it is o.k. to just wait for the next gc.
}
-
+
/*
* 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 +
@@ -108,4 +106,9 @@
throw new NullPointerException(name + " may not be null");
}
}
+
+ public void update(final TopicPermissions topicPermissions) {
+ checkNull(topicPermissions, "TopicPermissions");
+ m_topicPermissions = topicPermissions;
+ }
}
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 a27146a..95e4328 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
@@ -55,7 +55,7 @@
final ThreadPool m_pool;
/** The timeout for event handlers, 0 = disabled. */
- final long m_timeout;
+ long m_timeout;
private static interface Matcher
{
@@ -104,7 +104,7 @@
}
/** The matchers for ignore timeout handling. */
- private final Matcher[] m_ignoreTimeoutMatcher;
+ private Matcher[] m_ignoreTimeoutMatcher;
/**
* Construct a new sync deliver tasks.
@@ -114,6 +114,10 @@
public SyncDeliverTasks(final ThreadPool pool, final long timeout, final String[] ignoreTimeout)
{
m_pool = pool;
+ update(timeout, ignoreTimeout);
+ }
+
+ public void update(final long timeout, final String[] ignoreTimeout) {
m_timeout = timeout;
if ( ignoreTimeout == null || ignoreTimeout.length == 0 )
{
@@ -121,7 +125,7 @@
}
else
{
- m_ignoreTimeoutMatcher = new Matcher[ignoreTimeout.length];
+ Matcher[] ignoreTimeoutMatcher = new Matcher[ignoreTimeout.length];
for(int i=0;i<ignoreTimeout.length;i++)
{
String value = ignoreTimeout[i];
@@ -133,18 +137,19 @@
{
if ( value.endsWith(".") )
{
- m_ignoreTimeoutMatcher[i] = new PackageMatcher(value.substring(0, value.length() - 1));
+ ignoreTimeoutMatcher[i] = new PackageMatcher(value.substring(0, value.length() - 1));
}
else if ( value.endsWith("*") )
{
- m_ignoreTimeoutMatcher[i] = new SubPackageMatcher(value.substring(0, value.length() - 1));
+ ignoreTimeoutMatcher[i] = new SubPackageMatcher(value.substring(0, value.length() - 1));
}
else
{
- m_ignoreTimeoutMatcher[i] = new ClassMatcher(value);
+ ignoreTimeoutMatcher[i] = new ClassMatcher(value);
}
}
}
+ m_ignoreTimeoutMatcher = ignoreTimeoutMatcher;
}
}
@@ -158,14 +163,15 @@
// we only check the classname if a timeout is configured
if ( m_timeout > 0)
{
- if ( m_ignoreTimeoutMatcher != null )
+ final Matcher[] ignoreTimeoutMatcher = m_ignoreTimeoutMatcher;
+ if ( ignoreTimeoutMatcher != null )
{
final String className = task.getHandlerClassName();
- for(int i=0;i<m_ignoreTimeoutMatcher.length;i++)
+ for(int i=0;i<ignoreTimeoutMatcher.length;i++)
{
- if ( m_ignoreTimeoutMatcher[i] != null)
+ if ( ignoreTimeoutMatcher[i] != null)
{
- if ( m_ignoreTimeoutMatcher[i].match(className) )
+ if ( ignoreTimeoutMatcher[i].match(className) )
{
return false;
}