Repository: camel
Updated Branches:
  refs/heads/master 257f7df7d -> c3758e7e6


[CAMEL-7469] adding some synchronization for BP container and config admin 
updates


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e1442be3
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e1442be3
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e1442be3

Branch: refs/heads/master
Commit: e1442be3004d67f71a17342b6f90f7b7e03183b3
Parents: 26466b5
Author: Grzegorz Grzybek <gr.grzy...@gmail.com>
Authored: Wed May 28 14:41:05 2014 +0200
Committer: Grzegorz Grzybek <gr.grzy...@gmail.com>
Committed: Wed May 28 14:58:06 2014 +0200

----------------------------------------------------------------------
 .../blueprint/CamelBlueprintTestSupport.java    | 56 ++++++++++++++++++--
 1 file changed, 53 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e1442be3/components/camel-test-blueprint/src/main/java/org/apache/camel/test/blueprint/CamelBlueprintTestSupport.java
----------------------------------------------------------------------
diff --git 
a/components/camel-test-blueprint/src/main/java/org/apache/camel/test/blueprint/CamelBlueprintTestSupport.java
 
b/components/camel-test-blueprint/src/main/java/org/apache/camel/test/blueprint/CamelBlueprintTestSupport.java
index 96a5954..fc88f56 100644
--- 
a/components/camel-test-blueprint/src/main/java/org/apache/camel/test/blueprint/CamelBlueprintTestSupport.java
+++ 
b/components/camel-test-blueprint/src/main/java/org/apache/camel/test/blueprint/CamelBlueprintTestSupport.java
@@ -22,6 +22,8 @@ import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.component.properties.PropertiesComponent;
@@ -34,8 +36,12 @@ import org.junit.Before;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.blueprint.container.BlueprintContainer;
+import org.osgi.service.blueprint.container.BlueprintEvent;
+import org.osgi.service.blueprint.container.BlueprintListener;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
 
 /**
  * Base class for OSGi Blueprint unit tests with Camel.
@@ -62,8 +68,8 @@ public abstract class CamelBlueprintTestSupport extends 
CamelTestSupport {
    
     @SuppressWarnings({"rawtypes", "unchecked"})
     protected BundleContext createBundleContext() throws Exception {
-        String symbolicName = getClass().getSimpleName();
-        BundleContext answer = 
CamelBlueprintHelper.createBundleContext(symbolicName, getBlueprintDescriptor(),
+        final String symbolicName = getClass().getSimpleName();
+        final BundleContext answer = 
CamelBlueprintHelper.createBundleContext(symbolicName, getBlueprintDescriptor(),
             includeTestBundle(), getBundleFilter(), getBundleVersion(), 
getBundleDirectives());
 
         // must register override properties early in OSGi containers
@@ -101,14 +107,58 @@ public abstract class CamelBlueprintTestSupport extends 
CamelTestSupport {
         // allow end user to override properties
         String pid = useOverridePropertiesWithConfigAdmin(props);
         if (pid != null) {
+            // we will update the configuration now. As OSGi is highly 
asynchronous, we need to make the tests as repeatable as possible
+            // the problem is when blueprint container defines 
cm:property-placeholder with update-strategy="reload"
+            // updating the configuration leads to (felix framework + aries 
blueprint):
+            // 1. schedule 
org.apache.felix.cm.impl.ConfigurationManager.UpdateConfiguration object to run 
in config admin thread
+            // 2. this thread calls 
org.apache.felix.cm.impl.ConfigurationImpl#tryBindLocation()
+            // 3. org.osgi.service.cm.ConfigurationEvent#CM_LOCATION_CHANGED 
is send
+            // 4. 
org.apache.aries.blueprint.compendium.cm.ManagedObjectManager.ConfigurationWatcher#updated()
 is invoked
+            // 5. new Thread().start() is called
+            // 6. 
org.apache.aries.blueprint.compendium.cm.ManagedObject#updated() is called
+            // 7. 
org.apache.aries.blueprint.compendium.cm.CmPropertyPlaceholder#updated() is 
called
+            // 8. new Thread().start() is called
+            // 9. 
org.apache.aries.blueprint.services.ExtendedBlueprintContainer#reload() is 
called which destroys everything in BP container
+            // 10. finally reload of BP container is scheduled (in yet another 
thread)
+            //
+            // if we start/use camel context between point 9 and 10 we may get 
many different errors described in 
https://issues.apache.org/jira/browse/ARIES-961
+
+            // to synchronize this (main) thread of execution with the 
asynchronous series of events, we can register the following listener.
+            // this way be sure that we got to point 3
+            final CountDownLatch latch = new CountDownLatch(2);
+            answer.registerService(ConfigurationListener.class, new 
ConfigurationListener() {
+                @Override
+                public void configurationEvent(ConfigurationEvent event) {
+                    if (event.getType() == 
ConfigurationEvent.CM_LOCATION_CHANGED) {
+                        latch.countDown();
+                    }
+                    // when we update the configuration, BP container will be 
reloaded as well
+                    // hoping that we get the event after *second* restart, 
let's register the listener
+                    answer.registerService(BlueprintListener.class, new 
BlueprintListener() {
+                        @Override
+                        public void blueprintEvent(BlueprintEvent event) {
+                            if (event.getType() == BlueprintEvent.CREATED && 
event.getBundle().getSymbolicName().equals(symbolicName)) {
+                                latch.countDown();
+                            }
+                        }
+                    }, null);
+                }
+            }, null);
+
             ConfigurationAdmin configAdmin = 
CamelBlueprintHelper.getOsgiService(answer, ConfigurationAdmin.class);
-            Configuration config = configAdmin.getConfiguration(pid);
+            // passing null as second argument ties the configuration to 
correct bundle.
+            // using single-arg method causes:
+            // *ERROR* Cannot use configuration xxx.properties for 
[org.osgi.service.cm.ManagedService, id=N, bundle=N/jar:file:xyz.jar!/]: No 
visibility to configuration bound to file:pojosr
+            Configuration config = configAdmin.getConfiguration(pid, null);
             if (config == null) {
                 throw new IllegalArgumentException("Cannot find configuration 
with pid " + pid + " in OSGi ConfigurationAdmin service.");
             }
             log.info("Updating ConfigAdmin {} by overriding properties {}", 
config, props);
             config.update(props);
+
+            latch.await(CamelBlueprintHelper.DEFAULT_TIMEOUT, 
TimeUnit.MILLISECONDS);
         }
+
         return answer;
     }
 

Reply via email to