Author: pderop
Date: Sat Feb 20 21:15:24 2016
New Revision: 1731471
URL: http://svn.apache.org/viewvc?rev=1731471&view=rev
Log:
FELIX-5192: ConfigurationDependency race condition when component is stopped.
FELIX-5193: Factory Pid Adapter race condition when component is stopped.
Removed Eclipse warnings. Reworked the way configuration exception is handled.
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.benchmark/src/org/apache/felix/dm/benchmark/controller/impl/ScenarioControllerImpl.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/api/AspectWithCallbacksServiceDependencyTest.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AbstractDecorator.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/org/apache/felix/dm/impl/ConfigurationDependencyImplTest.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/test/Ensure.java
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.benchmark/src/org/apache/felix/dm/benchmark/controller/impl/ScenarioControllerImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.benchmark/src/org/apache/felix/dm/benchmark/controller/impl/ScenarioControllerImpl.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.benchmark/src/org/apache/felix/dm/benchmark/controller/impl/ScenarioControllerImpl.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.benchmark/src/org/apache/felix/dm/benchmark/controller/impl/ScenarioControllerImpl.java
Sat Feb 20 21:15:24 2016
@@ -299,17 +299,6 @@ public class ScenarioControllerImpl impl
}
/**
- * Initialize the latches used to track when all scenario bundle
components are started or stopped.
- */
- private void initLatches() {
- m_startLatch = new CountDownLatch(ARTISTS
- + (ARTISTS * (ALBUMS + (ALBUMS * TRACKS))));
-
- m_stopLatch = new CountDownLatch(ARTISTS
- + (ARTISTS * (ALBUMS + (ALBUMS * TRACKS))));
- }
-
- /**
* Returns the time consumed by the given runnable, ²ch is executed by
this method.
*/
private long durationOf(Runnable scenario) {
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/api/AspectWithCallbacksServiceDependencyTest.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/api/AspectWithCallbacksServiceDependencyTest.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/api/AspectWithCallbacksServiceDependencyTest.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/api/AspectWithCallbacksServiceDependencyTest.java
Sat Feb 20 21:15:24 2016
@@ -20,11 +20,8 @@ package org.apache.felix.dm.itest.api;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
-import org.apache.felix.dm.itest.api.AspectBaseTest.ServiceAspect;
-import org.apache.felix.dm.itest.api.AspectBaseTest.ServiceInterface;
import org.apache.felix.dm.itest.util.Ensure;
import org.apache.felix.dm.itest.util.TestBase;
-import org.osgi.framework.ServiceReference;
/**
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java
Sat Feb 20 21:15:24 2016
@@ -21,7 +21,6 @@ package org.apache.felix.dependencymanag
import java.io.IOException;
import java.util.Hashtable;
-import
org.apache.felix.dependencymanager.samples.hello.api.ServiceConsumerConf;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.log.LogService;
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java
Sat Feb 20 21:15:24 2016
@@ -18,8 +18,6 @@
*/
package org.apache.felix.dependencymanager.samples.hello.annot;
-import java.util.Dictionary;
-
import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ConfigurationDependency;
import org.apache.felix.dm.annotation.api.ServiceDependency;
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java
Sat Feb 20 21:15:24 2016
@@ -18,8 +18,7 @@
*/
package org.apache.felix.dependencymanager.samples.hello.api;
-import java.util.Dictionary;
-
+import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.log.LogService;
/**
@@ -32,7 +31,7 @@ public class ServiceConsumer {
volatile LogService log;
ServiceConsumerConf conf;
- protected void updated(ServiceConsumerConf conf) {
+ protected void updated(ServiceConsumerConf conf) throws
ConfigurationException {
this.conf = conf;
}
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AbstractDecorator.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AbstractDecorator.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AbstractDecorator.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/AbstractDecorator.java
Sat Feb 20 21:15:24 2016
@@ -40,14 +40,16 @@ import org.osgi.service.cm.Configuration
public abstract class AbstractDecorator {
protected volatile DependencyManager m_manager;
private final Map<Object, Component> m_services = new
ConcurrentHashMap<>();
-
- public abstract Component createService(Object[] properties);
+ private volatile ComponentContext m_decoratorComponent;
+
+ public abstract Component createService(Object[] properties) throws
Exception;
/**
* Catches our DependencyManager handle from our component init method.
*/
public void init(Component c) {
m_manager = c.getDependencyManager();
+ m_decoratorComponent = (ComponentContext) c;
}
/**
@@ -55,8 +57,8 @@ public abstract class AbstractDecorator
* For now, it's only used by the FactoryConfigurationAdapterImpl class,
* but it might also make sense to use this for Resource Adapters ...
*/
- public void updateService(Object[] properties) {
- throw new NoSuchMethodError("Method updateService not implemented");
+ public void updateService(Object[] properties) throws Exception {
+ throw new NoSuchMethodException("Method updateService not
implemented");
}
/**
@@ -104,29 +106,27 @@ public abstract class AbstractDecorator
}
}
- // callbacks for FactoryConfigurationAdapterImpl
- public void updated(String pid, @SuppressWarnings("rawtypes") Dictionary
properties) throws ConfigurationException {
- try {
- Component service = m_services.get(pid);
- if (service == null) {
- service = createService(new Object[] { properties });
- m_services.put(pid, service);
- m_manager.add(service);
- }
- else {
- updateService(new Object[] { properties, service });
- }
- }
- catch (Throwable t) {
- if (t instanceof ConfigurationException) {
- throw (ConfigurationException) t;
- }
- else if (t.getCause() instanceof ConfigurationException) {
- throw (ConfigurationException) t.getCause();
- }
- else {
- throw new ConfigurationException(null, "Could not create
service for ManagedServiceFactory Pid " + pid, t);
- }
+ // callbacks for FactoryConfigurationAdapterImpl from the ConfigAdmin
thread
+ @SuppressWarnings("rawtypes")
+ public void updated(String pid, Dictionary properties) throws
ConfigurationException {
+ // FELIX-5193: invoke the updated callback in the internal decorator
component queue, in order
+ // to safely detect if the component is still active or not.
+ InvocationUtil.invokeUpdated(m_decoratorComponent.getExecutor(), () ->
updatedSafe(pid, properties));
+ }
+
+ @SuppressWarnings("rawtypes")
+ private void updatedSafe(String pid, Dictionary properties) throws
Exception {
+ if (!m_decoratorComponent.isActive()) {
+ // Our decorator component has been removed: ignore the
configuration update.
+ return;
+ }
+ Component service = m_services.get(pid);
+ if (service == null) {
+ service = createService(new Object[] { properties });
+ m_services.put(pid, service);
+ m_manager.add(service);
+ } else {
+ updateService(new Object[] { properties, service });
}
}
@@ -138,7 +138,7 @@ public abstract class AbstractDecorator
}
// callbacks for resources
- public void added(URL resource) {
+ public void added(URL resource) throws Exception {
Component newService = createService(new Object[] { resource });
m_services.put(resource, newService);
m_manager.add(newService);
@@ -153,7 +153,7 @@ public abstract class AbstractDecorator
}
// callbacks for services
- public void added(ServiceReference ref, Object service) {
+ public void added(ServiceReference ref, Object service) throws Exception {
Component newService = createService(new Object[] { ref, service });
m_services.put(ref, newService);
m_manager.add(newService);
@@ -177,7 +177,7 @@ public abstract class AbstractDecorator
}
// callbacks for bundles
- public void added(Bundle bundle) {
+ public void added(Bundle bundle) throws Exception {
Component newService = createService(new Object[] { bundle });
m_services.put(bundle, newService);
m_manager.add(newService);
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java
Sat Feb 20 21:15:24 2016
@@ -112,6 +112,7 @@ public final class Configurable {
return result;
}
+ @SuppressWarnings("unchecked")
private Object convert(ParameterizedType type, String key, Object
value) throws Exception {
Class<?> resultType = (Class<?>) type.getRawType();
if (Class.class.isAssignableFrom(resultType)) {
@@ -171,6 +172,7 @@ public final class Configurable {
throw new RuntimeException("Unhandled type: " + type);
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
private Object convert(Type type, String key, Object value, boolean
useImplicitDefault) throws Exception {
if (type instanceof ParameterizedType) {
return convert((ParameterizedType) type, key, value);
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
Sat Feb 20 21:15:24 2016
@@ -18,16 +18,10 @@
*/
package org.apache.felix.dm.impl;
-import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.Objects;
import java.util.Properties;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
@@ -61,7 +55,6 @@ public class ConfigurationDependencyImpl
private final Logger m_logger;
private final BundleContext m_context;
private boolean m_needsInstance = true;
- private final static int UPDATE_MAXWAIT = 30000; // max time to wait
until a component has handled a configuration change event.
public ConfigurationDependencyImpl() {
this(null, null);
@@ -250,7 +243,7 @@ public class ConfigurationDependencyImpl
}
return m_settings;
}
-
+
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public void updated(final Dictionary settings) throws
ConfigurationException {
@@ -272,43 +265,12 @@ public class ConfigurationDependencyImpl
// callback is invoked safely. So, we use a Callable and a FutureTask
that allows to handle the
// configuration update through the component executor. We still wait
for the result because
// in case of any configuration error, we have to return it from the
current thread.
+ // Notice that scheduling the handling of the configuration update in
the component queue also
+ // allows to safely check if the component is still active (it could
be being stopped concurrently:
+ // see the invokeUpdated method which tests if our dependency is still
alive (by calling super.istarted()
+ // method).
- Callable<ConfigurationException> result = new
Callable<ConfigurationException>() {
- @Override
- public ConfigurationException call() throws Exception {
- try {
- invokeUpdated(settings); // either the callback instance
or the component instances, if available.
- } catch (ConfigurationException e) {
- return e;
- }
- return null;
- }
- };
-
- // Schedule the configuration update in the component executor. In
Normal case, the task is immediately executed.
- // But in a highly concurrent system, and if the component is being
reconfigured, the component may be currently busy
- // (handling a service dependency event for example), so the task will
be enqueued in the component executor, and
- // we'll wait for the task execution by using a FutureTask:
-
- FutureTask<ConfigurationException> ft = new FutureTask<>(result);
- m_component.getExecutor().execute(ft);
-
- try {
- ConfigurationException confError = ft.get(UPDATE_MAXWAIT,
TimeUnit.MILLISECONDS);
- if (confError != null) {
- throw confError; // will be logged by the Configuration Admin
service;
- }
- }
-
- catch (ExecutionException error) {
- throw new ConfigurationException(null, "Configuration update
error, unexpected exception.", error);
- } catch (InterruptedException error) {
- // will be logged by the Configuration Admin service;
- throw new ConfigurationException(null, "Configuration update
interrupted.", error);
- } catch (TimeoutException error) {
- // will be logged by the Configuration Admin service;
- throw new ConfigurationException(null, "Component did not handle
configuration update timely.", error);
- }
+ InvocationUtil.invokeUpdated(m_component.getExecutor(), () ->
invokeUpdated(settings));
// At this point, we have accepted the configuration.
synchronized (this) {
@@ -337,8 +299,8 @@ public class ConfigurationDependencyImpl
case ADDED:
try {
invokeUpdated(m_settings);
- } catch (ConfigurationException e) {
- logConfigurationException(e);
+ } catch (Throwable err) {
+ logConfigurationException(err);
}
break;
case CHANGED:
@@ -386,9 +348,18 @@ public class ConfigurationDependencyImpl
return new CallbackTypeDef(sigs, args);
}
- private void invokeUpdated(Dictionary<?, ?> settings) throws
ConfigurationException {
+ // Called from the configuration component internal queue.
+ private void invokeUpdated(Dictionary<?, ?> settings) throws Exception {
if (m_updateInvokedCache.compareAndSet(false, true)) {
+ // FELIX-5192: we have to handle the following race condition: one
thread stops a component (removes it from a DM object);
+ // another thread removes the configuration (from
ConfigurationAdmin). in this case we may be called in our
+ // ManagedService.updated(null), but our component instance has
been destroyed and does not exist anymore.
+ // In this case: do nothing.
+ if (! super.isStarted()) {
+ return;
+ }
+
// FELIX-5155: if component impl is an internal DM adapter, we
must not invoke the callback on it
// because in case there is an external callback instance
specified for the configuration callback,
// then we don't want to invoke it now. The external callback
instance will be invoked
@@ -400,11 +371,8 @@ public class ConfigurationDependencyImpl
return;
}
- Object[] instances = super.getInstances(); // either the callback
instance or the component instances
- if (instances == null) {
- return;
- }
-
+ Object[] instances = super.getInstances(); // never null, either
the callback instance or the component instances
+
CallbackTypeDef callbackInfo = createCallbackType(m_logger,
m_component, m_configType, settings);
boolean callbackFound = false;
for (int i = 0; i < instances.length; i++) {
@@ -412,24 +380,9 @@ public class ConfigurationDependencyImpl
InvocationUtil.invokeCallbackMethod(instances[i], m_add,
callbackInfo.m_sigs, callbackInfo.m_args);
callbackFound |= true;
}
- catch (InvocationTargetException e) {
- // The component has thrown an exception during it's
callback invocation.
- if (e.getTargetException() instanceof
ConfigurationException) {
- // the callback threw an OSGi ConfigurationException:
just re-throw it.
- throw (ConfigurationException) e.getTargetException();
- }
- else {
- // wrap the callback exception into a
ConfigurationException.
- throw new ConfigurationException(null, "Configuration
update failed", e.getTargetException());
- }
- }
catch (NoSuchMethodException e) {
// if the method does not exist, ignore it
}
- catch (Throwable t) {
- // wrap any other exception as a ConfigurationException.
- throw new ConfigurationException(null, "Configuration
update failed", t);
- }
}
if (! callbackFound) {
@@ -445,7 +398,7 @@ public class ConfigurationDependencyImpl
}
}
- private void logConfigurationException(ConfigurationException e) {
- m_logger.log(Logger.LOG_ERROR, "Got exception while handling
configuration update for pid " + m_pid, e);
+ private void logConfigurationException(Throwable err) {
+ m_logger.log(Logger.LOG_ERROR, "Got exception while handling
configuration update for pid " + m_pid, err);
}
}
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
Sat Feb 20 21:15:24 2016
@@ -18,7 +18,8 @@
*/
package org.apache.felix.dm.impl;
-import java.lang.reflect.InvocationTargetException;
+import static
org.apache.felix.dm.impl.ConfigurationDependencyImpl.createCallbackType;
+
import java.util.Arrays;
import java.util.Dictionary;
import java.util.Enumeration;
@@ -36,8 +37,6 @@ import org.osgi.service.cm.ManagedServic
import org.osgi.service.metatype.MetaTypeProvider;
import org.osgi.service.metatype.ObjectClassDefinition;
-import static
org.apache.felix.dm.impl.ConfigurationDependencyImpl.createCallbackType;
-
/**
* Factory configuration adapter service implementation. This class extends
the FilterService in order to catch
* some Service methods for configuring actual adapter service implementation.
@@ -128,7 +127,7 @@ public class FactoryConfigurationAdapter
* Method called from our superclass, when we need to create a service.
*/
@SuppressWarnings("unchecked")
- public Component createService(Object[] properties) {
+ public Component createService(Object[] properties) throws Exception {
Dictionary<String, ?> settings = (Dictionary<String, ?>)
properties[0];
Component newService = m_manager.createComponent();
@@ -160,7 +159,7 @@ public class FactoryConfigurationAdapter
* the configuration has changed.
*/
@SuppressWarnings("unchecked")
- public void updateService(Object[] properties) {
+ public void updateService(Object[] properties) throws Exception {
Dictionary<String, ?> cmSettings = (Dictionary<String, ?>)
properties[0];
Component service = (Component) properties[1];
CallbackTypeDef callbackInfo = createCallbackType(m_logger,
service, m_configType, cmSettings);
@@ -173,7 +172,7 @@ public class FactoryConfigurationAdapter
}
}
- private void invokeUpdated(Component service, CallbackTypeDef
callbackInfo) {
+ private void invokeUpdated(Component service, CallbackTypeDef
callbackInfo) throws Exception {
boolean callbackFound = false;
Object[] instances = getUpdateCallbackInstances(service);
for (Object instance : instances) {
@@ -181,16 +180,9 @@ public class FactoryConfigurationAdapter
InvocationUtil.invokeCallbackMethod(instance, m_update,
callbackInfo.m_sigs, callbackInfo.m_args);
callbackFound |= true;
}
- catch (InvocationTargetException e) {
- // The component has thrown an exception during it's
callback invocation.
- handleException(e.getTargetException());
- }
catch (NoSuchMethodException e) {
// if the method does not exist, ignore it
}
- catch (Throwable t) {
- handleException(t); // will rethrow a runtime exception.
- }
}
if (! callbackFound) {
@@ -247,25 +239,6 @@ public class FactoryConfigurationAdapter
return props;
}
-
- private void handleException(Throwable t) {
- if (m_logger != null) {
- m_logger.log(Logger.LOG_ERROR, "Got exception while handling
configuration update for factory pid " + m_factoryPid, t);
- } else {
-
- }
- if (t instanceof InvocationTargetException) {
- // Our super class will check if the target exception is
itself a ConfigurationException.
- // In this case, it will simply re-thrown.
- throw new RuntimeException(((InvocationTargetException)
t).getTargetException());
- }
- else if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- }
- else {
- throw new RuntimeException(t);
- }
- }
}
/**
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/InvocationUtil.java
Sat Feb 20 21:15:24 2016
@@ -25,6 +25,12 @@ import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+
+import org.osgi.service.cm.ConfigurationException;
/**
* Utility methods for invoking callbacks. Lookups of callbacks are
accellerated by using a LRU cache.
@@ -47,6 +53,19 @@ public class InvocationUtil {
}
/**
+ * Interface internally used to handle a ConfigurationAdmin update
synchronously, in a component executor queue.
+ */
+ @FunctionalInterface
+ public interface ConfigurationHandler {
+ public void handle() throws Exception;
+ }
+
+ /**
+ * Max time to wait until a configuration update callback has returned.
+ */
+ private final static int UPDATED_MAXWAIT = 30000; // max time to wait
until a CM update has completed
+
+ /**
* Invokes a callback method on an instance. The code will search for a
callback method with
* the supplied name and any of the supplied signatures in order, invoking
the first one it finds.
*
@@ -202,4 +221,44 @@ public class InvocationUtil {
return size() > m_size;
}
}
+
+ /**
+ * Invokes a configuration update callback synchronously, but through the
component executor queue.
+ */
+ public static void invokeUpdated(Executor queue, ConfigurationHandler
handler) throws ConfigurationException {
+ Callable<Exception> result = () -> {
+ try {
+ handler.handle();
+ } catch (Exception e) {
+ return e;
+ }
+ return null;
+ };
+
+ FutureTask<Exception> ft = new FutureTask<>(result);
+ queue.execute(ft);
+
+ try {
+ Exception err = ft.get(UPDATED_MAXWAIT, TimeUnit.MILLISECONDS);
+ if (err != null) {
+ throw err;
+ }
+ }
+
+ catch (ConfigurationException e) {
+ throw e;
+ }
+
+ catch (Throwable error) {
+ Throwable rootCause = error.getCause();
+ if (rootCause != null) {
+ if (rootCause instanceof ConfigurationException) {
+ throw (ConfigurationException) rootCause;
+ }
+ throw new ConfigurationException("", "Configuration update
error, unexpected exception.", rootCause);
+ } else {
+ throw new ConfigurationException("", "Configuration update
error, unexpected exception.", error);
+ }
+ }
+ }
}
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/org/apache/felix/dm/impl/ConfigurationDependencyImplTest.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/org/apache/felix/dm/impl/ConfigurationDependencyImplTest.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/org/apache/felix/dm/impl/ConfigurationDependencyImplTest.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/org/apache/felix/dm/impl/ConfigurationDependencyImplTest.java
Sat Feb 20 21:15:24 2016
@@ -75,6 +75,7 @@ public class ConfigurationDependencyImpl
super(ensure);
}
+ @SuppressWarnings("rawtypes")
@Override
public void updated(Dictionary config) throws ConfigurationException {
super.updated(config);
@@ -126,6 +127,7 @@ public class ConfigurationDependencyImpl
m_ensure = ensure;
}
+ @SuppressWarnings("rawtypes")
public void updated(Dictionary config) throws ConfigurationException {
m_ensure.step();
@@ -141,6 +143,7 @@ public class ConfigurationDependencyImpl
m_ensure.step();
}
+ @SuppressWarnings("rawtypes")
private void assertConfiguration(Dictionary cfg) {
assertEquals("isTrue", "true", cfg.get("true"));
assertEquals("getValue", "42", cfg.get("value"));
@@ -229,9 +232,11 @@ public class ConfigurationDependencyImpl
ConfigurationDependencyImpl result = new
ConfigurationDependencyImpl(bc, mockLogger);
result.setCallback(service, "updated").setPid("does.not.matter");
result.setComponentContext(component);
+ result.start();
return result;
}
+ @SuppressWarnings("rawtypes")
private Dictionary createDictionary() {
Dictionary<String, Object> result = new Hashtable<>();
result.put("true", "true");
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/test/Ensure.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/test/Ensure.java?rev=1731471&r1=1731470&r2=1731471&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/test/Ensure.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/test/test/Ensure.java
Sat Feb 20 21:15:24 2016
@@ -49,7 +49,7 @@ public class Ensure {
}
}
- public void setStream(PrintStream output) {
+ public static void setStream(PrintStream output) {
STREAM = output;
}