felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pde...@apache.org
Subject svn commit: r1564995 [15/17] - in /felix/sandbox/pderop/dependencymanager: ./ core/ core/.externalToolBuilders/ core/.settings/ core/src/ core/src/main/ core/src/main/java/ core/src/main/java/org/ core/src/main/java/org/apache/ core/src/main/java/org/a...
Date Wed, 05 Feb 2014 23:22:36 GMT
Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX3186_AspectAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX3186_AspectAdapterTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX3186_AspectAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX3186_AspectAdapterTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,152 @@
+/*
+ * 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.dm.test.integration.api;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Scenario: 
+ * 
+ * A service consumer consumes an adapter service. The adapter service adapts a service provider.
+ * An aspect is added to the service provider. This should not impact the service consumer.
+ * Expected behavior is transparent replacement of the service the adapter adapts with the aspect service.
+ *
+ */
+@RunWith(PaxExam.class)
+public class FELIX3186_AspectAdapterTest extends TestBase {
+    @Test
+    public void testAdapterWithAspectMultipleTimes() throws Exception {
+        // TODO this test is broken, it assumes that the order in which listeners are added to the BundleContext will also
+        // be the order in which they're invoked (which from a spec point of view is not true)
+        
+        
+        DependencyManager m = new DependencyManager(context);
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        
+        // create a service provider
+        Component provider = m.createComponent()
+            .setImplementation(new ServiceProvider())
+            .setInterface(OriginalService.class.getName(), null);
+
+        // create a adapter on the provider
+        Component adapter = m.createAdapterService(OriginalService.class, null)
+        .setInterface(AdaptedService.class.getName(), null)
+        .setImplementation(ServiceAdapter.class);
+        
+        // create a consumer for the adapted service
+        Component consumer = m.createComponent()
+            .setImplementation(new ServiceConsumer(e))
+            .add(m.createServiceDependency()
+                .setService(AdaptedService.class)
+                .setCallbacks("add", "remove")
+                .setRequired(true)
+            );
+        
+        // create an aspect on the service provider
+        Component aspect = m.createAspectService(OriginalService.class, null, 10, null)
+            .setImplementation(ServiceAspect.class);
+
+        // we first start the provider, the adapter and the consumer
+        m.add(provider);
+        m.add(adapter);
+        m.add(consumer);
+        // now wait until the callback method is invoked on the consumer
+        e.waitForStep(1, 5000);
+        // now we add an aspect on top of the provided service, which 
+        // should not affect our consumer at all
+        m.add(aspect);
+        m.remove(aspect);
+        // now we remove the consumer, adapter and provider
+        m.remove(consumer);
+        m.remove(adapter);
+        m.remove(provider);
+        // that should have triggered step 2
+        e.waitForStep(2, 5000);
+        // make sure we don't have extra steps by explicitly going to step 3
+        e.step(3);
+    }
+    
+    static interface OriginalService {
+        public void invoke();
+    }
+    
+    static interface AdaptedService {
+        public void invoke();
+    }
+    
+    static class ServiceProvider implements OriginalService {
+        public void invoke() {
+        }
+        
+        @Override
+        public String toString() {
+            return "Provider";
+        }
+    }
+    
+    public static class ServiceAdapter implements AdaptedService {
+        private volatile OriginalService m_originalService;
+        
+        public void invoke() {
+            m_originalService.invoke();
+        }
+        @Override
+        public String toString() {
+            return "Adapter on " + m_originalService;
+        }
+    }
+    
+    public static class ServiceAspect implements OriginalService {
+        volatile OriginalService m_service;
+        
+        public void invoke() {
+            m_service.invoke();
+        }
+        
+        @Override
+        public String toString() {
+            return "Aspect on " + m_service;
+        }
+    }
+
+    public static class ServiceConsumer {
+        Ensure m_ensure;
+        
+        public ServiceConsumer(Ensure e) {
+            m_ensure = e;
+        }
+        
+        public void add(ServiceReference ref, AdaptedService service) {
+            m_ensure.step();
+        }
+        public void remove(ServiceReference ref, AdaptedService service) {
+            m_ensure.step();
+        }
+    }
+}
+
+

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX3337_UpdatedConfigurationDependencyWithPropagationTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX3337_UpdatedConfigurationDependencyWithPropagationTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX3337_UpdatedConfigurationDependencyWithPropagationTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX3337_UpdatedConfigurationDependencyWithPropagationTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,151 @@
+/*
+ * 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.dm.test.integration.api;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+
+/**
+ * This test validates the following scenario:
+ * - Service S1 depends on a ConfigurationDependency with propagate = true
+ * - Service S2 depends on S1 (and has access to the S1 configuration using the S1 service 
+ *   properties (because the ConfigurationDependency is propagated)
+ * - then the S1 PID is updated from ConfigAdmin
+ * - S1 is then called in its updated callback
+ * - S2 is called in its "change" callback.
+ */
+@RunWith(PaxExam.class)
+public class FELIX3337_UpdatedConfigurationDependencyWithPropagationTest extends TestBase {    
+    /*
+     * This Pojo creates the configuration pid "test".
+     */
+    static class ConfigurationCreator {
+        private volatile ConfigurationAdmin m_ca;
+        org.osgi.service.cm.Configuration m_conf;
+        
+        public void init() {
+            try {
+                m_conf = m_ca.getConfiguration("test", null);
+                Hashtable props = new Properties();
+                props.put("testkey", "testvalue");
+                m_conf.update(props);
+            }
+            catch (IOException e) {
+                Assert.fail("Could not create configuration: " + e.getMessage());
+            }
+        }
+        
+        public void update() {
+            try {
+                Hashtable props = new Properties();
+                props.put("testkey", "testvalue");
+                props.put("testkey2", "testvalue2");
+                m_conf.update(props);
+            } catch (IOException e) {
+                Assert.fail("Could not update the configured property: " + e.toString());
+            }
+        }
+    }
+
+    static class S1 implements ManagedService {
+        private Ensure m_ensure;
+        private boolean m_initialized;
+
+        public S1(Ensure e) {
+            m_ensure = e;
+        }
+        
+        public void updated(Dictionary props) throws ConfigurationException {
+            if (! m_initialized) {
+                m_ensure.step(1);
+                m_initialized = true;
+            } else {
+                // we are updated
+                m_ensure.step(3);
+            }
+        }
+    }
+
+    static class S2 {
+        private final Ensure m_ensure;
+
+        public S2(Ensure e) {
+            m_ensure = e;
+        }
+                        
+        public void add(S1 s1) {
+            m_ensure.step(2);
+        }
+        
+        public void change(S1 runnable) {
+            m_ensure.step(4);
+        }
+    }
+    
+    @Test
+    public void testComponentWithRequiredUpdatedConfigurationAndServicePropertyPropagation() {
+        DependencyManager m = new DependencyManager(context);
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();        
+        ConfigurationCreator confCreator = new ConfigurationCreator();
+        Component s1 = m.createComponent()
+                .setImplementation(new S1(e))
+                .setInterface(S1.class.getName(), null)
+                .add(m.createConfigurationDependency()
+                     .setPid("test")
+                     .setPropagate(true));
+        Component s2 = m.createComponent()
+                .setImplementation(new S2(e))
+                .add(m.createServiceDependency()
+                     .setService(S1.class, ("(testkey=testvalue)"))
+                     .setRequired(true)
+                     .setCallbacks("add", "change", null));
+        Component s3 = m.createComponent()
+                .setImplementation(confCreator)
+                .add(m.createServiceDependency()
+                     .setService(ConfigurationAdmin.class)
+                     .setRequired(true));
+
+        m.add(s1);
+        m.add(s2);
+        m.add(s3);
+        e.waitForStep(2, 15000);
+        confCreator.update();
+        e.waitForStep(4, 15000);
+        m.remove(s1);
+        m.remove(s2);
+        m.remove(s3);
+    }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX4361_ConcurrentComponentListingTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX4361_ConcurrentComponentListingTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX4361_ConcurrentComponentListingTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FELIX4361_ConcurrentComponentListingTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,108 @@
+/*
+ * 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.dm.test.integration.api;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+
+/**
+ * Test for FELIX-4361 The DependencyManager.getComponents method failed in a concurrent situation on iterating the
+ * result of the method.
+ */
+@RunWith(PaxExam.class)
+public class FELIX4361_ConcurrentComponentListingTest extends TestBase {
+
+    @Test
+    public void testConcurrentGetComponentsManipulation() {
+        DependencyManager dm = new DependencyManager(context);
+        dm.add(dm.createComponent().setImplementation(Object.class));
+        Iterator iterator = dm.getComponents().iterator();
+        dm.add(dm.createComponent().setImplementation(Object.class));
+        iterator.next();
+    }
+
+    @Test
+    public void testConcurrentGetComponentsMultipleThreads() {
+        final DependencyManager m = new DependencyManager(context);
+        final AtomicInteger errors = new AtomicInteger(0);
+        final AtomicInteger componentsAdded = new AtomicInteger(0);
+        final int max = 10000;
+        final AtomicBoolean isRunning = new AtomicBoolean(true);
+
+        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
+        Runnable readTask = new Runnable() {
+            public void run() {
+                while (isRunning.get()) {
+                    try {
+                        List components = m.getComponents();
+                        for (Object component : components) {
+                            // Just iterating the components should check for concurrent modifications
+                        }
+                    }
+                    catch (Exception ex) {
+                        errors.addAndGet(1);
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        };
+
+        Callable<Boolean> modifyTask = new Callable<Boolean>() {
+            public Boolean call() throws Exception {
+                try {
+                    m.add(m.createComponent().setImplementation(Object.class));
+                    componentsAdded.addAndGet(1);
+                    return true;
+                }
+                catch (Exception ex) {
+                    return false;
+                }
+            }
+        };
+
+        executorService.submit(readTask);
+        for (int i = 0; i < max; i++) {
+            executorService.submit(modifyTask);
+        }
+        isRunning.set(false);
+        executorService.shutdown();
+
+        try {
+            executorService.awaitTermination(30, TimeUnit.SECONDS);
+        }
+        catch (InterruptedException e) {
+        }
+        Assert.assertEquals(0, errors.get());
+        Assert.assertEquals(max, componentsAdded.get());
+    }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FactoryConfigurationAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FactoryConfigurationAdapterTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FactoryConfigurationAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FactoryConfigurationAdapterTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,226 @@
+/*
+ * 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.dm.test.integration.api;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+@RunWith(PaxExam.class)
+public class FactoryConfigurationAdapterTest extends TestBase
+{
+    private static Ensure m_ensure;
+    
+    @Test
+    public void testFactoryConfigurationAdapter() {
+        DependencyManager m = new DependencyManager(context);
+        // helper class that ensures certain steps get executed in sequence
+        m_ensure = new Ensure();
+        
+        // Create a Configuration instance, which will create/update/remove a configuration for factoryPid "MyFactoryPid"
+        ConfigurationCreator configurator = new ConfigurationCreator("MyFactoryPid", "key", "value1");
+        Component s1 = m.createComponent()
+            .setImplementation(configurator)
+            .add(m.createServiceDependency()
+                .setService(ConfigurationAdmin.class)
+                .setRequired(true));
+
+        // Create an Adapter that will be instantiated, once the configuration is created.
+        // This Adapter provides an AdapterService, and depends on an AdapterExtraDependency service.
+        Component s2 = m.createFactoryConfigurationAdapterService("MyFactoryPid", "updated", true /* propagate CM settings */)
+                      .setInterface(AdapterService.class.getName(), new Properties() {{ put("foo", "bar"); }})
+                      .setImplementation(Adapter.class);
+
+        s2.add(m.createServiceDependency()
+            .setService(AdapterExtraDependency.class)
+            .setRequired(true)
+            .setAutoConfig(true));
+        
+        // Create extra adapter service dependency upon which our adapter depends on.
+        Component s3 = m.createComponent()
+            .setImplementation(new AdapterExtraDependency())
+            .setInterface(AdapterExtraDependency.class.getName(), null);
+        
+        // Create an AdapterService Consumer
+        Component s4 = m.createComponent()
+            .setImplementation(AdapterServiceConsumer.class)
+            .add(m.createServiceDependency()
+                .setService(AdapterService.class)
+                .setRequired(true)
+                .setCallbacks("bind", "change", "remove"));
+        
+        // Start services
+        m.add(s1);
+        m.add(s2);
+        m.add(s3);
+        m.add(s4);
+        
+        // Wait for step 8: the AdapterService consumer has been injected with the AdapterService, and has called the doService method.
+        m_ensure.waitForStep(8, 10000);
+        
+        // Modify configuration.
+        configurator.update("key", "value2");
+        
+        // Wait for step 13: the AdapterService has been updated, and the AdapterService consumer has seen the change
+        m_ensure.waitForStep(13, 10000);
+        
+        // Remove the configuration
+        m.remove(s1); // The stop method will remove the configuration
+        m_ensure.waitForStep(16, 10000);
+        m.clear();
+    }
+
+    public static class ConfigurationCreator {
+        private volatile ConfigurationAdmin m_ca;
+        private String m_key;
+        private String m_value;
+        private org.osgi.service.cm.Configuration m_conf;
+        private String m_factoryPid;
+        
+        public ConfigurationCreator(String factoryPid, String key, String value) {
+            m_factoryPid = factoryPid;
+            m_key = key;
+            m_value = value;
+        }
+
+        public void start() {
+            try {
+                m_ensure.step(1);
+                m_conf = m_ca.createFactoryConfiguration(m_factoryPid, null);
+                Hashtable props = new Hashtable();
+                props.put(m_key, m_value);
+                m_conf.update(props);
+            }
+            catch (IOException e) {
+                Assert.fail("Could not create configuration: " + e.getMessage());
+            }
+        }
+        
+        public void update(String key, String val) {
+            Hashtable props = new Hashtable();
+            props.put(key, val);
+            try {
+                m_conf.update(props);
+            }
+            catch (IOException e) {
+                Assert.fail("Could not update configuration: " + e.getMessage());
+            }
+        }
+        
+        public void stop() {
+            try
+            {
+                m_conf.delete();
+            }
+            catch (IOException e)
+            {
+                Assert.fail("Could not remove configuration: " + e.toString());
+            }
+        }
+    }
+    
+    public interface AdapterService {
+        public void doService();
+    }
+    
+    public static class AdapterExtraDependency {
+    }
+
+    public static class Adapter implements AdapterService {
+        volatile AdapterExtraDependency m_extraDependency; // extra dependency.
+        private int updateCount;
+        
+        void updated(Dictionary settings) {
+            updateCount ++;
+            if (updateCount == 1) {
+                m_ensure.step(2);
+                Assert.assertEquals(true, "value1".equals(settings.get("key")));
+                m_ensure.step(3);
+            } else if (updateCount == 2) {
+                m_ensure.step(9);
+                Assert.assertEquals(true, "value2".equals(settings.get("key")));
+                m_ensure.step(10);
+            } else {
+                Assert.fail("wrong call to updated method: count=" + updateCount);
+            }
+        }
+
+        public void doService() {   
+            m_ensure.step(8);
+        }
+        
+        public void start() {
+            m_ensure.step(4);
+            Assert.assertNotNull(m_extraDependency);
+            m_ensure.step(5);
+        }
+        
+        public void stop() {
+            m_ensure.step(16);
+        }
+    }
+
+    public static class AdapterServiceConsumer {
+        private AdapterService m_adapterService;
+        private Map m_adapterServiceProperties;
+        
+        void bind(Map serviceProperties, AdapterService adapterService) {
+            m_ensure.step(6);
+            m_adapterService = adapterService;
+            m_adapterServiceProperties = serviceProperties;
+        }
+        
+        void change(Map serviceProperties, AdapterService adapterService) {
+            m_ensure.step(11);
+            Assert.assertEquals(true, "value2".equals(m_adapterServiceProperties.get("key")));
+            m_ensure.step(12);
+            Assert.assertEquals(true, "bar".equals(m_adapterServiceProperties.get("foo")));
+            m_ensure.step(13);
+        }
+        
+        public void start() {
+            m_ensure.step(7);
+            Assert.assertNotNull(m_adapterService);
+            Assert.assertEquals(true, "value1".equals(m_adapterServiceProperties.get("key")));
+            Assert.assertEquals(true, "bar".equals(m_adapterServiceProperties.get("foo")));
+            m_adapterService.doService();
+        }
+        
+        public void stop() {
+            m_ensure.step(14);
+        }
+        
+        void remove(AdapterService adapterService) {
+            m_ensure.step(15);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FilterIndexResourceAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FilterIndexResourceAdapterTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FilterIndexResourceAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/FilterIndexResourceAdapterTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,179 @@
+/*
+ * 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.dm.test.integration.api;
+//import static org.ops4j.pax.exam.CoreOptions.waitForFrameworkStartupFor;
+//import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ResourceHandler;
+import org.apache.felix.dm.ResourceUtil;
+import org.apache.felix.dm.ServiceUtil;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+@RunWith(PaxExam.class)
+public class FilterIndexResourceAdapterTest extends TestBase {
+    @Test
+    public void testBasicResourceAdapter() throws Exception {
+        System.setProperty("org.apache.felix.dependencymanager.filterindex", "objectClass");
+        DependencyManager m = new DependencyManager(context);
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a resource provider
+        ResourceProvider provider = new ResourceProvider(e);
+        // activate it
+        m.add(m.createComponent().setImplementation(provider).add(m.createServiceDependency().setService(ResourceHandler.class).setCallbacks("add", "remove")));
+        // create a resource adapter for our single resource
+        // note that we can provide an actual implementation instance here because there will be only one
+        // adapter, normally you'd want to specify a Class here
+        m.add(m.createResourceAdapterService("(&(path=/path/to/*.txt)(host=localhost))", false, null, "changed")
+              .setImplementation(new ResourceAdapter(e)));
+        // wait until the single resource is available
+        e.waitForStep(3, 5000);
+        // trigger a 'change' in our resource
+        provider.change();
+        // wait until the changed callback is invoked
+        e.waitForStep(4, 5000);
+        m.clear();
+     }
+    
+    static class ResourceAdapter {
+        protected URL m_resource; // injected by reflection.
+        private Ensure m_ensure;
+        
+        ResourceAdapter(Ensure e) {
+            m_ensure = e;
+        }
+        
+        public void start() {
+            m_ensure.step(1);
+            Assert.assertNotNull("resource not injected", m_resource);
+            m_ensure.step(2);
+            try {
+                InputStream in = m_resource.openStream();
+            } 
+            catch (FileNotFoundException e) {
+                m_ensure.step(3);
+            }
+            catch (IOException e) {
+                Assert.fail("We should not have gotten this exception.");
+            }
+        }
+        
+        public void changed() {
+            m_ensure.step(4);
+        }
+    }
+    
+    static class ResourceProvider {
+        private volatile BundleContext m_context;
+        private final Ensure m_ensure;
+        private final Map m_handlers = new HashMap();
+        private URL[] m_resources;
+
+        public ResourceProvider(Ensure ensure) throws MalformedURLException {
+            m_ensure = ensure;
+            m_resources = new URL[] {
+                new URL("file://localhost/path/to/file1.txt")
+            };
+        }
+        
+        public void change() {
+            ResourceHandler[] handlers;
+            synchronized (m_handlers) {
+                handlers = (ResourceHandler[]) m_handlers.keySet().toArray(new ResourceHandler[m_handlers.size()]);
+            }
+            for (int i = 0; i < m_resources.length; i++) {
+                for (int j = 0; j < handlers.length; j++) {
+                    ResourceHandler handler = handlers[j];
+                    handler.changed(m_resources[i]);
+                }
+            }
+        }
+
+        public void add(ServiceReference ref, ResourceHandler handler) {
+            System.out.println("RP.add: " + ServiceUtil.toString(ref));
+            String filterString = (String) ref.getProperty("filter");
+            Filter filter = null;
+            if (filterString != null) {
+                try {
+                    filter = m_context.createFilter(filterString);
+                }
+                catch (InvalidSyntaxException e) {
+                    Assert.fail("Could not create filter for resource handler: " + e);
+                    return;
+                }
+            }
+            synchronized (m_handlers) {
+                m_handlers.put(handler, filter);
+            }
+            for (int i = 0; i < m_resources.length; i++) {
+                if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[i]))) {
+                    handler.added(m_resources[i]);
+                }
+            }
+        }
+
+        public void remove(ServiceReference ref, ResourceHandler handler) {
+            Filter filter;
+            synchronized (m_handlers) {
+                filter = (Filter) m_handlers.remove(handler);
+            }
+            removeResources(handler, filter);
+        }
+
+        private void removeResources(ResourceHandler handler, Filter filter) {
+                for (int i = 0; i < m_resources.length; i++) {
+                    if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[i]))) {
+                        handler.removed(m_resources[i]);
+                    }
+                }
+            }
+
+        public void destroy() {
+            Entry[] handlers;
+            synchronized (m_handlers) {
+                handlers = (Entry[]) m_handlers.entrySet().toArray(new Entry[m_handlers.size()]);
+            }
+            for (int i = 0; i < handlers.length; i++) {
+                removeResources((ResourceHandler) handlers[i].getKey(), (Filter) handlers[i].getValue());
+            }
+            
+            System.out.println("DESTROY..." + m_handlers.size());
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ModifiedBundleDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ModifiedBundleDependencyTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ModifiedBundleDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ModifiedBundleDependencyTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,145 @@
+/*
+ * 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.dm.test.integration.api;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+/**
+ * Test for FELIX-4334 issue.
+ * 
+ * Two components: A, B
+ * 
+ * - A provided.
+ * - B has a bundle dependency on the dependency manager shell bundle, which is currently stopped.
+ * - B has an instance bound dependency on A.
+ * - Now unregister A.
+ * - As a result of that, B becomes unavailable and is unbound from A. But B is not destroyed, because A dependency 
+ *   is "instance bound". So B is still bound to the bundle dependency.
+ * - Now, someone starts the dependency manager shell bundle: B then shall be called in its "changed" callback.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@RunWith(PaxExam.class)
+public class ModifiedBundleDependencyTest extends TestBase {
+    public static interface A {
+    }
+    
+    static class AImpl implements A {
+    }
+        
+    public static interface B {
+    }
+    
+    static class BImpl implements B {
+        final Ensure m_e;
+        
+        BImpl(Ensure e) {
+            m_e = e;
+        }
+        
+        public void add(Bundle dmTest) {
+            m_e.step(1);
+        }
+
+        void init(Component c) {
+            m_e.step(2);
+            DependencyManager dm = c.getDependencyManager();
+            c.add(dm.createServiceDependency().setService(A.class).setRequired(true).setInstanceBound(true).setCallbacks("add", "remove"));
+        }      
+        
+        public void add(A a) {
+            m_e.step(3);
+        }
+        
+        public void start() {
+            m_e.step(4);            
+        }
+        
+        public void stop() {
+            m_e.step(5);
+        }
+
+        public void remove(A a) {
+            m_e.step(6);
+        }
+
+        public void change(Bundle dmTest) { // called two times: one for STARTING, one for STARTED
+            m_e.step(); 
+        }
+        
+        public void destroy() {
+            m_e.step(9);
+        }
+
+        public void remove(Bundle dmTest) {   
+            m_e.step(10);
+        }                    
+    }
+    
+    @Test
+    public void testAdapterWithChangedInstanceBoundDependency() {
+        DependencyManager m = new DependencyManager(context);
+        Ensure e = new Ensure();
+
+        Component a = m.createComponent()
+                .setImplementation(new AImpl())
+                .setInterface(A.class.getName(), null);
+        
+        Component b = m.createComponent()
+                .setInterface(B.class.getName(), null)
+                .setImplementation(new BImpl(e))
+                .add(m.createBundleDependency()
+                        .setFilter("(Bundle-SymbolicName=org.apache.felix.dependencymanager.shell)")
+                        .setStateMask(Bundle.INSTALLED|Bundle.ACTIVE|Bundle.RESOLVED|Bundle.STARTING)
+                        .setRequired(true)
+                        .setCallbacks("add", "change", "remove"));
+                    
+        Bundle dmtest = getBundle("org.apache.felix.dependencymanager.shell");
+        try {
+            dmtest.stop();
+        } catch (BundleException e1) {
+            Assert.fail("couold not find dependencymanager shell bundle");
+        }
+        
+        m.add(a);
+        m.add(b);
+        
+        e.waitForStep(4, 5000);        
+        m.remove(a); // B will loose A and will enter into "waiting for required (instantiated)" state.
+        System.out.println("Starting dependency manager shell ...");        
+        try {
+            dmtest.start();
+        } catch (BundleException e1) {
+            Assert.fail("could not start dependencymanager shell bundle");
+        }
+        e.waitForStep(7, 5000);     
+        m.remove(b);        
+        e.waitForStep(10, 5000);                
+    }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependenciesTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependenciesTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependenciesTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependenciesTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,220 @@
+/*
+ * 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.dm.test.integration.api;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+
+@RunWith(PaxExam.class)
+public class MultipleExtraDependenciesTest extends TestBase {
+    /**
+     * Check that list of extra dependencies (defined from init method) are handled properly.
+     * The extra dependencies are added using a List object (Component.add(List)).
+     * A component c1 will define two extra dependencies over *available* c4/c5 services.
+     */
+     @Test
+     public void testWithTwoAvailableExtraDependency() {   
+         DependencyManager m = new DependencyManager(context);
+         // Helper class that ensures certain steps get executed in sequence
+         Ensure e = new Ensure();
+         Component c1 = m.createComponent()
+                         .setInterface(Service1.class.getName(), null)
+                         .setImplementation(new MyComponent1(e))
+                         .add(m.createServiceDependency()
+                              .setService(Service2.class)
+                              .setRequired(true)
+                              .setAutoConfig("m_service2"));
+         
+         Component c2 = m.createComponent()
+                         .setImplementation(new MyComponent2(e))
+                         .add(m.createServiceDependency()
+                              .setService(Service1.class)
+                              .setRequired(false)
+                              .setAutoConfig(false)
+                              .setCallbacks("added", null, null));
+              
+         Component c3 = m.createComponent()
+                         .setInterface(Service2.class.getName(), null)
+                         .setImplementation(Service2Impl.class);
+         
+         Hashtable h = new Hashtable();
+         h.put("type", "xx");
+         Component c4 = m.createComponent()
+                         .setInterface(Service3.class.getName(), h)
+                         .setImplementation(Service3Impl1.class);
+
+         h = new Hashtable();
+         h.put("type", "yy");
+         Component c5 = m.createComponent()
+                         .setInterface(Service3.class.getName(), h)
+                         .setImplementation(Service3Impl2.class);
+
+
+         System.out.println("\n+++ Adding c2 / MyComponent2");
+         m.add(c2);
+         System.out.println("\n+++ Adding c3 / Service2");
+         m.add(c3);
+         System.out.println("\n+++ Adding c4 / Service3(xx)");
+         m.add(c4);
+         System.out.println("\n+++ Adding c5 / Service3(yy)");
+         m.add(c5);
+         System.out.println("\n+++ Adding c1 / MyComponent1");
+         // c1 have declared two extra dependency on Service3 (xx/yy).
+         // both extra dependencies are available, so the c1 component should be started immediately.
+         m.add(c1);
+         e.waitForStep(3, 3000);
+         m.clear();
+     }
+
+    /**
+     * Check that list of extra dependencies (defined from init method) are handled properly.
+     * The extra dependencies are added using a List object (Component.add(List)).
+     * A component c1 will define two extra dependencies over c4/c5. At the point c1.init()
+     * is adding the two extra dependencies from its init method, c4 is available, but not c5.
+     * So, c1 is not yet activated.
+     * Then c5 is added, and it triggers the c1 activation ...
+     */
+   @Test
+    public void testWithOneAvailableExtraDependency() {  
+        DependencyManager m = new DependencyManager(context);
+        // Helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        Component c1 = m.createComponent()
+                        .setInterface(Service1.class.getName(), null)
+                        .setImplementation(new MyComponent1(e))
+                        .add(m.createServiceDependency()
+                             .setService(Service2.class)
+                             .setRequired(true)
+                             .setAutoConfig("m_service2"));
+        
+        Component c2 = m.createComponent()
+                        .setImplementation(new MyComponent2(e))
+                        .add(m.createServiceDependency()
+                             .setService(Service1.class)
+                             .setRequired(false)
+                             .setAutoConfig(false)
+                             .setCallbacks("added", null, null));
+             
+        Component c3 = m.createComponent()
+                        .setInterface(Service2.class.getName(), null)
+                        .setImplementation(Service2Impl.class);
+        
+        Hashtable h = new Hashtable();
+        h.put("type", "xx");
+        Component c4 = m.createComponent()
+                        .setInterface(Service3.class.getName(), h)
+                        .setImplementation(Service3Impl1.class);
+
+        h = new Hashtable();
+        h.put("type", "yy");
+        Component c5 = m.createComponent()
+                        .setInterface(Service3.class.getName(), h)
+                        .setImplementation(Service3Impl2.class);
+
+
+        System.out.println("\n+++ Adding c2 / MyComponent2");
+        m.add(c2);
+        System.out.println("\n+++ Adding c3 / Service2");
+        m.add(c3);
+        System.out.println("\n+++ Adding c4 / Service3(xx)");
+        m.add(c4);
+        System.out.println("\n+++ Adding c1 / MyComponent1");
+        m.add(c1);
+
+        // c1 have declared two extra dependency on Service3 (xx/yy).
+        // So, because we have not yet added c5 (yy), c1 should not be started currently.
+        // But, now, we'll add c5 (Service3/yy) and c1 should then be started ...
+        System.out.println("\n+++ Adding c5 / Service3(yy)");
+        m.add(c5);
+        e.waitForStep(3, 3000);
+        m.clear();
+    }
+
+
+    public interface Service1 {}
+    public interface Service2 {}
+    public interface Service3 {}
+
+    public static class Service2Impl implements Service2 {}
+    public static class Service3Impl1 implements Service3 {}
+    public static class Service3Impl2 implements Service3 {}
+
+    public static class MyComponent1 implements Service1 {
+        Service1 m_service2;
+        Service2 m_service3_xx;
+        Service2 m_service3_yy;
+        Ensure m_ensure;
+        
+        public MyComponent1(Ensure e) {
+            m_ensure = e;
+        }
+
+        void init(Component c) {
+            m_ensure.step(1);
+            DependencyManager dm = c.getDependencyManager();
+            List l = new ArrayList();
+            // Service3/xx currently available
+            l.add(dm.createServiceDependency()
+                     .setInstanceBound(true)
+                     .setService(Service3.class, "(type=xx)")
+                     .setRequired(true)
+                     .setAutoConfig("m_service3_xx"));
+            
+            // Service3/yy not yet available
+            l.add(dm.createServiceDependency()
+                  .setInstanceBound(true)
+                  .setService(Service3.class, "(type=yy)")
+                  .setRequired(true)
+                  .setAutoConfig("m_service3_yy"));
+            c.add(l);
+        }
+        
+        void start() {
+            System.out.println("MyComponent1.start");
+            m_ensure.step(2);
+        }
+    }
+    
+    public static class MyComponent2 {
+        Service1 m_service1;
+        Ensure m_ensure;
+        
+        public MyComponent2(Ensure e) {
+            m_ensure = e;
+        }
+
+        void added(Service1 s1) {
+            System.out.println("MyComponent2.bind(" + s1 + ")");
+            m_ensure.step(3);
+        }
+        
+        void start() {
+            System.out.println("MyComponent2.start");
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependencyTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependencyTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,229 @@
+/*
+ * 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.dm.test.integration.api;
+
+import java.util.Hashtable;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+/**
+ * Test which validates multi-dependencies combination.
+ */
+import org.ops4j.pax.exam.junit.PaxExam;
+
+@RunWith(PaxExam.class)
+public class MultipleExtraDependencyTest extends TestBase {
+    @Test
+    public void testMultipleExtraDependencies()
+    {
+        DependencyManager m = new DependencyManager(context);
+        Ensure e = new Ensure();
+        
+        Component sp2 = m.createComponent()
+              .setImplementation(ServiceProvider2.class).setInterface(ServiceProvider2.class.getName(), null)
+              .add(m.createServiceDependency()
+                   .setService(Runnable.class, "(foo=bar)")
+                   .setRequired(false)
+                   .setAutoConfig("m_runnable"))
+              .add(m.createServiceDependency()
+                   .setService(Sequencer.class)
+                   .setRequired(true)
+                   .setCallbacks("bind", null))
+              .setCallbacks(null, "start", "stop", null)
+              .setComposition("getComposition");
+        
+        Component sp = m.createComponent()
+              .setImplementation(ServiceProvider.class)
+              .setInterface(ServiceInterface.class.getName(), 
+                            new Hashtable() {{ put("foo", "bar"); }})
+              .add(m.createServiceDependency()
+                   .setService(Sequencer.class)
+                   .setRequired(true)
+                   .setAutoConfig("m_sequencer"))
+               .add(m.createServiceDependency()
+                   .setService(ServiceProvider2.class)
+                   .setRequired(true)
+                   .setCallbacks("bind", "unbind"))
+              .setCallbacks(null, "start", "stop", null);
+        
+        Component sc = m.createComponent()
+              .setImplementation(ServiceConsumer.class)
+              .add(m.createServiceDependency()
+                   .setService(Sequencer.class)
+                   .setRequired(true)
+                   .setAutoConfig("m_sequencer"))
+               .add(m.createServiceDependency()
+                   .setService(ServiceInterface.class, "(foo=bar)")
+                   .setRequired(true)
+                   .setAutoConfig("m_service"))
+              .setCallbacks(null, "start", "stop", null);
+        
+        // Provide the Sequencer service to the MultipleAnnotationsTest class.
+        Component sequencer = 
+            m.createComponent().setImplementation(new SequencerImpl(e))
+                             .setInterface(Sequencer.class.getName(), null);
+        m.add(sp2);
+        m.add(sp);
+        m.add(sc);
+        m.add(sequencer);
+        
+        // Check if the test.annotation components have been initialized orderly
+        e.waitForStep(7, 10000);
+        
+        // Stop the test.annotation bundle
+        m.remove(sequencer);
+        m.remove(sp);
+        m.remove(sp2);
+        m.remove(sc);
+        
+        // And check if the test.annotation bundle has been deactivated orderly
+        e.waitForStep(11, 10000);
+    }
+    
+    public interface Sequencer
+    {
+        void step();
+        void step(int step);
+        void waitForStep(int step, int timeout);
+    }
+    
+    public static class SequencerImpl implements Sequencer {
+        Ensure m_ensure;
+        
+        public SequencerImpl(Ensure e)
+        {
+            m_ensure = e;
+        }
+        
+        public void step()
+        {
+            m_ensure.step();
+        }
+
+        public void step(int step)
+        {
+            m_ensure.step(step);
+        }
+
+        public void waitForStep(int step, int timeout)
+        {
+            m_ensure.waitForStep(step, timeout);
+        }  
+    }
+    
+    public interface ServiceInterface
+    {
+        public void doService();
+    }
+    
+    public static class ServiceConsumer
+    {
+        volatile Sequencer m_sequencer;
+        volatile ServiceInterface m_service;
+
+        void start()
+        {
+            m_sequencer.step(6);
+            m_service.doService();
+        }
+
+        void stop()
+        {
+            m_sequencer.step(8);
+        }
+    }
+    
+    public static class ServiceProvider implements ServiceInterface
+    {
+        Sequencer m_sequencer;
+        ServiceProvider2 m_serviceProvider2;
+
+        void bind(ServiceProvider2 provider2)
+        {
+            m_serviceProvider2 = provider2;
+        }
+
+        void start()
+        {
+            m_serviceProvider2.step(4);
+            m_sequencer.step(5);
+        }
+
+        void stop()
+        {
+            m_sequencer.step(9);
+        }
+
+        void unbind(ServiceProvider2 provider2)
+        {
+            m_sequencer.step(10);
+        }
+
+        public void doService()
+        {
+            m_sequencer.step(7);
+        }
+    }
+
+    public static class ServiceProvider2
+    {
+        Composite m_composite = new Composite();
+        Sequencer m_sequencer;
+        Runnable m_runnable;
+
+        void bind(Sequencer seq)
+        {
+            m_sequencer = seq;
+            m_sequencer.step(1);
+        }
+
+        void start()
+        {
+            m_sequencer.step(3);
+            m_runnable.run(); // NullObject
+        }
+
+        public void step(int step) // called by ServiceProvider.start() method 
+        { 
+            m_sequencer.step(step);
+        }
+        
+        void stop()
+        {
+            m_sequencer.step(11);
+        }
+
+        Object[] getComposition()
+        {
+            return new Object[] { this, m_composite };
+        }
+    }
+    
+    public static class Composite
+    {
+        void bind(Sequencer seq)
+        {
+            seq.step(2);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependencyTest2.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependencyTest2.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependencyTest2.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleExtraDependencyTest2.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,272 @@
+/*
+ * 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.dm.test.integration.api;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ServiceDependency;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+
+
+/**
+ * Tests for extra dependencies which are declared from service's init method.
+ */
+@RunWith(PaxExam.class)
+public class MultipleExtraDependencyTest2 extends TestBase {
+    @Test
+    public void testMultipleExtraDependencies()
+    {
+        DependencyManager m = new DependencyManager(context);
+        Ensure e = new Ensure();
+        
+        Component sp2 = m.createComponent()
+            .setImplementation(ServiceProvider2.class).setInterface(ServiceProvider2.class.getName(), null)
+            .setCallbacks("init", "start", "stop", null)
+            .setComposition("getComposition");
+        
+        Component sp = m.createComponent()
+              .setImplementation(ServiceProvider.class)
+              .setInterface(ServiceInterface.class.getName(), new Hashtable() {{ put("foo", "bar"); }})                            
+              .setCallbacks("init", "start", "stop", null);
+        
+        Component sc = m.createComponent()
+              .setImplementation(ServiceConsumer.class)
+              .setCallbacks("init", "start", "stop", null);
+        
+        // Provide the Sequencer service to the MultipleAnnotationsTest class.
+        Component sequencer = 
+            m.createComponent().setImplementation(new SequencerImpl(e))
+                             .setInterface(Sequencer.class.getName(), null);
+        m.add(sp2);
+        m.add(sp);
+        m.add(sc);
+        m.add(sequencer);
+
+        // Check if the test.annotation components have been initialized orderly
+        e.waitForStep(7, 10000);
+        
+        // Stop the test.annotation bundle
+        m.remove(sequencer);
+        m.remove(sp);
+        m.remove(sp2);
+        m.remove(sc);
+        
+//        m.remove(sp2);
+//        m.remove(sc);
+//        m.remove(sp);
+//        m.remove(sequencer);
+        
+
+        
+        // And check if the test.annotation bundle has been deactivated orderly
+        e.waitForStep(11, 10000);
+        m.clear();
+    }
+    
+    public interface Sequencer
+    {
+        void step();
+        void step(int step);
+        void waitForStep(int step, int timeout);
+    }
+    
+    public static class SequencerImpl implements Sequencer {
+        final Ensure m_ensure;
+        
+        public SequencerImpl(Ensure e)
+        {
+            m_ensure = e;
+        }
+        
+        public void step()
+        {
+            m_ensure.step();
+        }
+
+        public void step(int step)
+        {
+            m_ensure.step(step);
+        }
+
+        public void waitForStep(int step, int timeout)
+        {
+            m_ensure.waitForStep(step, timeout);
+        }  
+    }
+    
+    public interface ServiceInterface
+    {
+        public void doService();
+    }
+    
+    public static class ServiceConsumer {
+        volatile Sequencer m_sequencer;
+        volatile ServiceInterface m_service;
+        volatile ServiceDependency m_d1, m_d2;
+
+        public void init(Component s) {
+            DependencyManager m = s.getDependencyManager();
+            s.add(m_d1 = m.createServiceDependency()
+                .setService(Sequencer.class)
+                .setRequired(true)
+                .setInstanceBound(true)
+                .setAutoConfig("m_sequencer"));
+            s.add(m_d2 = m.createServiceDependency()
+                .setService(ServiceInterface.class, "(foo=bar)")
+                .setRequired(true)
+                .setInstanceBound(true)
+                .setAutoConfig("m_service"));
+        }
+        
+        void start() {
+            m_sequencer.step(6);
+            m_service.doService();
+        }
+
+        void stop() {
+            m_sequencer.step(8);
+        }
+    }
+    
+    public static class ServiceProvider implements ServiceInterface
+    {
+        volatile Sequencer m_sequencer;
+        volatile ServiceProvider2 m_serviceProvider2;
+        volatile ServiceDependency m_d1, m_d2;
+
+        public void init(Component c)
+        {
+            DependencyManager m = c.getDependencyManager();
+            List<ServiceDependency> l = new ArrayList<ServiceDependency>();
+            l.add(m_d1 = m.createServiceDependency()
+                    .setService(Sequencer.class)
+                    .setRequired(true)
+                    .setInstanceBound(true)
+                    .setAutoConfig("m_sequencer"));
+            l.add(m_d2 = m.createServiceDependency()
+                    .setService(ServiceProvider2.class)
+                    .setRequired(true)
+                    .setInstanceBound(true)
+                    .setCallbacks("bind", "unbind"));
+            c.add(l);
+        }
+        
+        void bind(ServiceProvider2 provider2)
+        {
+            m_serviceProvider2 = provider2;
+        }
+
+        void start()
+        {
+            m_d1.setInstanceBound(false);
+            m_d2.setInstanceBound(false);
+            m_serviceProvider2.step(4);
+            m_sequencer.step(5);
+        }
+
+        void stop()
+        {
+            m_sequencer.step(9);
+        }
+
+        void unbind(ServiceProvider2 provider2)
+        {
+            m_sequencer.step(10);
+        }
+
+        public void doService()
+        {
+            m_sequencer.step(7);
+        }
+    }
+
+    public static class ServiceProvider2
+    {
+        final Composite m_composite = new Composite();
+        volatile Sequencer m_sequencer;
+        volatile Runnable m_runnable;
+        volatile ServiceDependency m_d1, m_d2;
+
+        public void init(Component c)
+        {
+            System.out.println("ServiceProvider2.init");
+            DependencyManager m = c.getDependencyManager();
+            List<ServiceDependency> l = new ArrayList<ServiceDependency>();
+            
+            l.add(m_d1 = m.createServiceDependency()
+                  .setService(Runnable.class, "(foo=bar)")
+                  .setRequired(false)
+                  .setInstanceBound(true)
+                  .setAutoConfig("m_runnable"));
+            l.add(m_d2 = m.createServiceDependency()
+                  .setService(Sequencer.class)
+                  .setRequired(true)
+                  .setInstanceBound(true)
+                  .setCallbacks("bind", null));
+            c.add(l);
+        }
+        
+        void bind(Sequencer seq)
+        {
+            System.out.println("ServiceProvider2.bind(" + seq + ")");
+            m_sequencer = seq;
+            m_sequencer.step(1);
+        }
+
+        void start()
+        {
+            System.out.println("ServiceProvider2.start: m_runnable=" + m_runnable + ", m_sequencer = " + m_sequencer);
+            m_d1.setInstanceBound(false);
+            m_d2.setInstanceBound(false);
+            m_sequencer.step(3);
+            m_runnable.run(); // NullObject
+        }
+
+        public void step(int step) // called by ServiceProvider.start() method 
+        { 
+            m_sequencer.step(step);
+        }
+        
+        void stop()
+        {
+            m_sequencer.step(11);
+        }
+
+        Object[] getComposition()
+        {
+            return new Object[] { this, m_composite };
+        }
+    }
+    
+    public static class Composite
+    {
+        void bind(Sequencer seq)
+        {
+            seq.step(2);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleServiceDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleServiceDependencyTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleServiceDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/MultipleServiceDependencyTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,150 @@
+/*
+ * 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.dm.test.integration.api;
+
+import java.util.Properties;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.Constants;
+
+@RunWith(PaxExam.class)
+public class MultipleServiceDependencyTest extends TestBase {
+   @Test
+   public void testMultipleServiceRegistrationAndConsumption() {
+       DependencyManager m = new DependencyManager(context);
+       // helper class that ensures certain steps get executed in sequence
+       Ensure e = new Ensure();
+       // create a service provider and consumer
+       Component provider = m.createComponent().setImplementation(new ServiceProvider(e)).setInterface(ServiceInterface.class.getName(), null);
+       Component providerWithHighRank = m.createComponent().setImplementation(new ServiceProvider2(e)).setInterface(ServiceInterface.class.getName(), new Properties() {{ put(Constants.SERVICE_RANKING, Integer.valueOf(5)); }});
+       Component consumer = m.createComponent().setImplementation(new ServiceConsumer(e)).add(m.createServiceDependency().setService(ServiceInterface.class).setRequired(true));
+       m.add(provider);
+       m.add(providerWithHighRank);
+       m.add(consumer);
+       e.waitForStep(3, 15000);
+       m.remove(providerWithHighRank);
+       e.step(4);
+       e.waitForStep(5, 15000);
+       m.remove(provider);
+       m.remove(consumer);
+       e.waitForStep(6, 15000);
+   }
+
+   @Test
+   public void testReplacementAutoConfig() {
+       DependencyManager m = new DependencyManager(context);
+       // helper class that ensures certain steps get executed in sequence
+       Ensure e = new Ensure();
+       // create a service provider and consumer
+       Component provider = m.createComponent().setImplementation(new ServiceProvider(e)).setInterface(ServiceInterface.class.getName(), null);
+       Component provider2 = m.createComponent().setImplementation(new ServiceProvider2(e)).setInterface(ServiceInterface.class.getName(), null);
+       Component consumer = m.createComponent().setImplementation(new ServiceConsumer(e)).add(m.createServiceDependency().setService(ServiceInterface.class).setRequired(true));
+       m.add(provider2);
+       m.add(consumer);
+       e.waitForStep(3, 15000);
+       m.add(provider);
+       m.remove(provider2);
+       e.step(4);
+       e.waitForStep(5, 15000);
+       m.remove(provider);
+       m.remove(consumer);
+       e.waitForStep(6, 15000);
+   }
+
+   @Test
+   public void testReplacementCallbacks() {
+       DependencyManager m = new DependencyManager(context);
+       // helper class that ensures certain steps get executed in sequence
+       Ensure e = new Ensure();
+       // create a service provider and consumer
+       Component provider = m.createComponent().setImplementation(new ServiceProvider(e)).setInterface(ServiceInterface.class.getName(), null);
+       Component provider2 = m.createComponent().setImplementation(new ServiceProvider2(e)).setInterface(ServiceInterface.class.getName(), null);
+       Component consumer = m.createComponent().setImplementation(new ServiceConsumer(e))
+         .add(m.createServiceDependency()
+              .setService(ServiceInterface.class)
+              .setRequired(true)
+              .setCallbacks("add", "remove"));
+       m.add(provider2);
+       m.add(consumer);
+       e.waitForStep(3, 15000);
+       m.add(provider);
+       m.remove(provider2);
+       e.step(4);
+       e.waitForStep(5, 15000);
+       m.remove(provider);
+       m.remove(consumer);
+       e.waitForStep(6, 15000);
+   }
+
+   static interface ServiceInterface {
+       public void invoke();
+   }
+
+   static class ServiceProvider implements ServiceInterface {
+       private final Ensure m_ensure;
+       public ServiceProvider(Ensure e) {
+           m_ensure = e;
+       }
+       public void invoke() {
+           m_ensure.step(5);
+       }
+   }
+
+   static class ServiceProvider2 implements ServiceInterface {
+       private final Ensure m_ensure;
+       public ServiceProvider2(Ensure e) {
+           m_ensure = e;
+       }
+       public void invoke() {
+           m_ensure.step(2);
+       }
+   }
+
+   static class ServiceConsumer implements Runnable {
+       private volatile ServiceInterface m_service;
+       private final Ensure m_ensure;
+
+       private void add(ServiceInterface service) { m_service = service; }
+       private void remove(ServiceInterface service) { if (m_service == service) { m_service = null; }};
+       public ServiceConsumer(Ensure e) { m_ensure = e; }
+
+       public void start() {
+           Thread t = new Thread(this);
+           t.start();
+       }
+
+       public void run() {
+           m_ensure.step(1);
+           m_service.invoke();
+           m_ensure.step(3);
+           m_ensure.waitForStep(4, 15000);
+           m_service.invoke();
+       }
+
+       public void stop() {
+           m_ensure.step(6);
+       }
+   }
+}

Added: felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ResourceAdapterDependencyAddAndRemoveTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ResourceAdapterDependencyAddAndRemoveTest.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ResourceAdapterDependencyAddAndRemoveTest.java (added)
+++ felix/sandbox/pderop/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ResourceAdapterDependencyAddAndRemoveTest.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,271 @@
+/*
+ * 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.dm.test.integration.api;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ComponentStateListener;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ResourceHandler;
+import org.apache.felix.dm.ResourceUtil;
+import org.apache.felix.dm.ServiceDependency;
+import org.apache.felix.dm.test.components.Ensure;
+import org.apache.felix.dm.test.integration.common.TestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+@RunWith(PaxExam.class)
+public class ResourceAdapterDependencyAddAndRemoveTest extends TestBase {
+    @Test
+    public void testBasicResourceAdapter() throws Exception {
+        DependencyManager m = new DependencyManager(context);
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+
+        // create and add a service provider
+        m.add(m.createComponent()
+        		.setInterface(ServiceInterface.class.getName(), null)
+        		.setImplementation(new ServiceProvider(e)));
+        
+        // create and add a resource provider
+        ResourceProvider provider = new ResourceProvider(e);
+        m.add(m.createComponent()
+        		.setImplementation(provider)
+        		.add(m.createServiceDependency()
+        			.setService(ResourceHandler.class)
+        			.setCallbacks("add", "remove"))
+        		);
+        
+        // create a resource adapter for our single resource
+        // note that we can provide an actual implementation instance here because there will be only one
+        // adapter, normally you'd want to specify a Class here
+        // also, create a callback instance which will be used for both callbacks on resource changes and
+        // life cycle callbacks on the adapters themselves
+        CallbackInstance callbackInstance = new CallbackInstance(e);
+        Component component = m.createResourceAdapterService("(&(path=/path/to/*.txt)(host=localhost))", false, callbackInstance, "changed")
+            .setImplementation(new ResourceAdapter(e))
+            .setCallbacks(callbackInstance, "init", "start", "stop", "destroy")
+            .add(m.createServiceDependency()
+      			.setService(ServiceInterface.class)
+      			.setRequired(true)
+      			.setInstanceBound(true));
+        // add a component state listener
+        component.addStateListener(new ComponentStateListenerImpl(e));
+        // add the resource adapter
+        m.add(component);
+        // wait until the single resource is available (the adapter has been started)
+        e.waitForStep(1, 5000);
+        // trigger a 'change' in our resource
+        provider.change();
+        // wait until the changed callback is invoked
+        e.waitForStep(2, 5000);
+        // and has completed (ensuring no "extra" steps are invoked in the mean time)
+        e.waitForStep(3, 5000);
+        
+        // remove the resource adapter again
+        m.remove(component);
+        
+        // wait for the stopped callback in the state listener
+        e.waitForStep(4, 5000);
+     }
+    
+    static class ResourceAdapter {
+        protected URL m_resource; // injected by reflection.
+        private Ensure m_ensure;
+        
+        ResourceAdapter(Ensure e) {
+            m_ensure = e;
+        }
+        
+    }
+    
+    static class ResourceProvider {
+        private volatile BundleContext m_context;
+        private final Ensure m_ensure;
+        private final Map m_handlers = new HashMap();
+        private URL[] m_resources;
+
+        public ResourceProvider(Ensure ensure) throws MalformedURLException {
+            m_ensure = ensure;
+            m_resources = new URL[] {
+                new URL("file://localhost/path/to/file1.txt")
+            };
+        }
+        
+        public void change() {
+            ResourceHandler[] handlers;
+            synchronized (m_handlers) {
+                handlers = (ResourceHandler[]) m_handlers.keySet().toArray(new ResourceHandler[m_handlers.size()]);
+            }
+            for (int i = 0; i < m_resources.length; i++) {
+                for (int j = 0; j < handlers.length; j++) {
+                    ResourceHandler handler = handlers[j];
+                    handler.changed(m_resources[i]);
+                }
+            }
+        }
+
+        public void add(ServiceReference ref, ResourceHandler handler) {
+            String filterString = (String) ref.getProperty("filter");
+            Filter filter = null;
+            if (filterString != null) {
+                try {
+                    filter = m_context.createFilter(filterString);
+                }
+                catch (InvalidSyntaxException e) {
+                    Assert.fail("Could not create filter for resource handler: " + e);
+                    return;
+                }
+            }
+            synchronized (m_handlers) {
+                m_handlers.put(handler, filter);
+            }
+            for (int i = 0; i < m_resources.length; i++) {
+                if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[i]))) {
+                    handler.added(m_resources[i]);
+                }
+            }
+        }
+
+        public void remove(ServiceReference ref, ResourceHandler handler) {
+            Filter filter;
+            synchronized (m_handlers) {
+                filter = (Filter) m_handlers.remove(handler);
+            }
+            removeResources(handler, filter);
+        }
+
+        private void removeResources(ResourceHandler handler, Filter filter) {
+                for (int i = 0; i < m_resources.length; i++) {
+                    if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[i]))) {
+                        handler.removed(m_resources[i]);
+                    }
+                }
+            }
+
+        public void destroy() {
+            Entry[] handlers;
+            synchronized (m_handlers) {
+                handlers = (Entry[]) m_handlers.entrySet().toArray(new Entry[m_handlers.size()]);
+            }
+            for (int i = 0; i < handlers.length; i++) {
+                removeResources((ResourceHandler) handlers[i].getKey(), (Filter) handlers[i].getValue());
+            }
+            
+            System.out.println("DESTROY..." + m_handlers.size());
+        }
+    }
+    
+    static interface ServiceInterface {
+        public void invoke();
+    }
+
+    static class ServiceProvider implements ServiceInterface {
+        private final Ensure m_ensure;
+        public ServiceProvider(Ensure e) {
+            m_ensure = e;
+        }
+        public void invoke() {
+        }
+    }    
+    
+    static class CallbackInstance {
+    	
+    	private final Ensure m_ensure;
+    	
+    	public CallbackInstance(Ensure e) {
+    		m_ensure = e;
+    	}
+    	
+    	void init() {
+    		System.out.println("init");
+    	}
+    	
+    	void start() {
+    		System.out.println("start");
+    		m_ensure.step(1);
+    	}
+    	
+    	void stop() {
+    		System.out.println("stop");
+    	}
+    	
+    	void destroy() {
+    		System.out.println("destroy");
+    	}
+    	
+    	void changed(Component component) {
+    		m_ensure.step(2);
+    		Dependency oldDependency = null;
+    		
+    		for (Object dependency : component.getDependencies()) {
+    			if (dependency instanceof ServiceDependency) {
+    				// remove the dependency
+    				oldDependency = (Dependency) dependency;
+    			}
+    		}
+    		
+    		// and add a new dependency
+    		component.add(component.getDependencyManager().createServiceDependency().setService(ServiceInterface.class).setRequired(true).setInstanceBound(true));
+    		// remove the old dependency
+    		component.remove(oldDependency);
+    		System.out.println("Changed the dependencies");
+            m_ensure.step(3);
+    	}
+    }
+    
+    static class ComponentStateListenerImpl implements ComponentStateListener {
+    	
+    	private final Ensure m_ensure;
+    	
+    	public ComponentStateListenerImpl(Ensure e) {
+    		this.m_ensure = e;
+    	}
+
+		public void started(Component c) {
+			System.out.println("started");
+		}
+
+		public void starting(Component c) {
+			System.out.println("starting");
+		}
+
+		public void stopped(Component c) {
+			System.out.println("stopped");
+			m_ensure.step(4);
+		}
+
+		public void stopping(Component c) {
+			System.out.println("stopping");
+		}
+    }
+}



Mime
View raw message