Author: pderop
Date: Sat Apr 17 18:23:35 2010
New Revision: 935222

URL: http://svn.apache.org/viewvc?rev=935222&view=rev
Log:
ConfigAdmin factory configuration adapter support

Added:
    
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
    
felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
Modified:
    
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
    
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
    
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java

Modified: 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java?rev=935222&r1=935221&r2=935222&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
 (original)
+++ 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
 Sat Apr 17 18:23:35 2010
@@ -186,6 +186,46 @@ public abstract class DependencyActivato
     }
 
     /**
+     * Creates a new Managed Service Factory Configuration Adapter. For each 
new Config Admin factory configuration matching
+     * the factoryPid, an adapter will be created based on the adapter 
implementation class.
+     * The adapter will be registered with the specified interface, and with 
the specified adapter service properties.
+     * Depending on the <code>propagate</code> parameter, every public factory 
configuration properties 
+     * (which don't start with ".") will be propagated along with the adapter 
service properties. 
+     * It will also inherit all dependencies.
+     * 
+     * @param factoryPid the pid matching the factory configuration
+     * @param update the adapter method name that will be notified when the 
factory configuration is created/updated.
+     * @param adapterInterface the interface to use when registering adapters 
(can be either a String, String array) 
+     * @param adapterImplementation the implementation of the adapter (can be 
a Class or an Object instance)
+     * @param adapterProperties additional properties to use with the service 
registration
+     * @param propagate true if public factory configuration should be 
propagated to the adapter service properties
+     * @return a service that acts as a factory for generating the managed 
service factory configuration adapter
+     */
+    public Service createFactoryConfigurationAdapterService(String factoryPid, 
String update, Object adapterImplementation, String adapterInterface, 
Dictionary adapterProperties, boolean propagate) {
+        return m_manager.createFactoryConfigurationAdapterService(factoryPid, 
update, adapterImplementation, adapterInterface, adapterProperties, propagate);
+    }
+    
+    /**
+     * Creates a new Managed Service Factory Configuration Adapter. For each 
new Config Admin factory configuration matching
+     * the factoryPid, an adapter will be created based on the adapter 
implementation class.
+     * The adapter will be registered with the specified interface, and with 
the specified adapter service properties.
+     * Depending on the <code>propagate</code> parameter, every public factory 
configuration properties 
+     * (which don't start with ".") will be propagated along with the adapter 
service properties. 
+     * It will also inherit all dependencies.
+     * 
+     * @param factoryPid the pid matching the factory configuration
+     * @param update the adapter method name that will be notified when the 
factory configuration is created/updated.
+     * @param adapterInterfaces the interfaces to use when registering 
adapters (can be either a String, String array) 
+     * @param adapterImplementation the implementation of the adapter (can be 
a Class or an Object instance)
+     * @param adapterProperties additional properties to use with the service 
registration
+     * @param propagate true if public factory configuration should be 
propagated to the adapter service properties
+     * @return a service that acts as a factory for generating the managed 
service factory configuration adapter
+     */
+   public Service createFactoryConfigurationAdapterService(String factoryPid, 
String update, Object adapterImplementation, String[] adapterInterfaces, 
Dictionary adapterProperties, boolean propagate) {
+        return m_manager.createFactoryConfigurationAdapterService(factoryPid, 
update, adapterImplementation, adapterInterfaces, adapterProperties, propagate);
+    }
+
+    /**
      * Cleans up all services and their dependencies.
      * 
      * @param manager the dependency manager

Modified: 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java?rev=935222&r1=935221&r2=935222&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
 (original)
+++ 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
 Sat Apr 17 18:23:35 2010
@@ -21,6 +21,7 @@ package org.apache.felix.dm;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Dictionary;
+import java.util.Hashtable;
 import java.util.List;
 
 import org.apache.felix.dm.dependencies.BundleDependency;
@@ -33,6 +34,7 @@ import org.apache.felix.dm.impl.AdapterI
 import org.apache.felix.dm.impl.AspectImpl;
 import org.apache.felix.dm.impl.BundleAdapterImpl;
 import org.apache.felix.dm.impl.Logger;
+import org.apache.felix.dm.impl.FactoryConfigurationAdapterImpl;
 import org.apache.felix.dm.impl.ResourceAdapterImpl;
 import org.apache.felix.dm.impl.ServiceImpl;
 import org.apache.felix.dm.impl.dependencies.BundleDependencyImpl;
@@ -44,6 +46,8 @@ import org.apache.felix.dm.impl.metatype
 import org.apache.felix.dm.resources.Resource;
 import org.apache.felix.dm.service.Service;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedServiceFactory;
 
 /**
  * The dependency manager manages all services and their dependencies. Using 
@@ -318,6 +322,54 @@ public class DependencyManager {
     }
 
     /**
+     * Creates a new Managed Service Factory Configuration Adapter. For each 
new Config Admin factory configuration matching
+     * the factoryPid, an adapter will be created based on the adapter 
implementation class.
+     * The adapter will be registered with the specified interface, and with 
the specified adapter service properties.
+     * Depending on the <code>propagate</code> parameter, every public factory 
configuration properties 
+     * (which don't start with ".") will be propagated along with the adapter 
service properties. 
+     * It will also inherit all dependencies.
+     * 
+     * @param factoryPid the pid matching the factory configuration
+     * @param update the adapter method name that will be notified when the 
factory configuration is created/updated.
+     * @param adapterInterface the interface to use when registering adapters 
(can be either a String, String array) 
+     * @param adapterImplementation the implementation of the adapter (can be 
a Class or an Object instance)
+     * @param adapterProperties additional properties to use with the service 
registration
+     * @param propagate true if public factory configuration should be 
propagated to the adapter service properties
+     * @return a service that acts as a factory for generating the managed 
service factory configuration adapter
+     */
+    public Service createFactoryConfigurationAdapterService(String factoryPid, 
String update, Object adapterImplementation, String adapterInterface, 
Dictionary adapterProperties, boolean propagate) {
+        Hashtable props = new Hashtable();
+        props.put(Constants.SERVICE_PID, factoryPid);
+        return createService()
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(new FactoryConfigurationAdapterImpl(factoryPid, 
update, adapterImplementation, adapterInterface, adapterProperties, propagate));
+    }
+    
+    /**
+     * Creates a new Managed Service Factory Configuration Adapter. For each 
new Config Admin factory configuration matching
+     * the factoryPid, an adapter will be created based on the adapter 
implementation class.
+     * The adapter will be registered with the specified interface, and with 
the specified adapter service properties.
+     * Depending on the <code>propagate</code> parameter, every public factory 
configuration properties 
+     * (which don't start with ".") will be propagated along with the adapter 
service properties. 
+     * It will also inherit all dependencies.
+     * 
+     * @param factoryPid the pid matching the factory configuration
+     * @param update the adapter method name that will be notified when the 
factory configuration is created/updated.
+     * @param adapterInterfaces the interfaces to use when registering 
adapters (can be either a String, String array) 
+     * @param adapterImplementation the implementation of the adapter (can be 
a Class or an Object instance)
+     * @param adapterProperties additional properties to use with the service 
registration
+     * @param propagate true if public factory configuration should be 
propagated to the adapter service properties
+     * @return a service that acts as a factory for generating the managed 
service factory configuration adapter
+     */
+    public Service createFactoryConfigurationAdapterService(String factoryPid, 
String update, Object adapterImplementation, String[] adapterInterfaces, 
Dictionary adapterProperties, boolean propagate) {
+        Hashtable props = new Hashtable();
+        props.put(Constants.SERVICE_PID, factoryPid);
+        return createService()
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(new FactoryConfigurationAdapterImpl(factoryPid, 
update, adapterImplementation, adapterInterfaces, adapterProperties, 
propagate));
+    }
+
+    /**
      * Returns a list of services.
      * 
      * @return a list of services

Modified: 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java?rev=935222&r1=935221&r2=935222&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
 (original)
+++ 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
 Sat Apr 17 18:23:35 2010
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.dm.impl;
 
+import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -27,12 +28,60 @@ import org.apache.felix.dm.resources.Res
 import org.apache.felix.dm.service.Service;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
 
-public abstract class AbstractDecorator {
+public abstract class AbstractDecorator  {
     protected volatile DependencyManager m_manager;
     private final Map m_services = new HashMap();
     
     public abstract Service createService(Object[] properties);
+    
+    /**
+     * Extra method, which may be used by sub-classes, when adaptee has 
changed.
+     * For now, it's only used by the FactoryConfigurationAdapterImpl class, 
+     * but it might also make sense to use this for Resource Adapters ...
+     */
+    public void updateService(Object[] properties) {
+        throw new NoSuchMethodError("Method updateService not implemented");
+    }
+    
+    // callbacks for FactoryConfigurationAdapterImpl
+    public void updated(String pid, Dictionary properties) throws 
ConfigurationException {
+        try {
+            Service service = (Service) m_services.get(pid);
+            if (service == null) { 
+                service = createService(new Object[] { properties });
+                synchronized (this) {
+                    m_services.put(pid, service);
+                }
+                m_manager.add(service);
+            } else {
+                updateService(new Object[] { properties, service });
+            }
+        }
+        
+        catch (Throwable t) {
+            if (t instanceof ConfigurationException) {
+                throw (ConfigurationException) t;
+            } else if (t.getCause() instanceof ConfigurationException) {
+                throw (ConfigurationException) t.getCause();
+            } else {
+                throw new ConfigurationException(null, "Could not create 
service for ManagedServiceFactory Pid " + pid, t);
+            }
+        }
+    }
+
+    public synchronized void deleted(String pid)
+    {
+        Service service = null;
+        synchronized (this) {
+            service = (Service) m_services.remove(pid);
+        }
+        if (service != null)
+        {
+            m_manager.remove(service);
+        }
+    }
 
     // callbacks for resources
     public void added(Resource resource) {
@@ -94,5 +143,5 @@ public abstract class AbstractDecorator 
             m_manager.remove((Service) i.next());
         }
         m_services.clear();
-    }
+    }    
 }

Added: 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java?rev=935222&view=auto
==============================================================================
--- 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
 (added)
+++ 
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
 Sat Apr 17 18:23:35 2010
@@ -0,0 +1,206 @@
+/*
+ * 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.impl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.service.Service;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+/**
+ * Creates, updates, or removes a service, when a ConfigAdmin factory 
configuration is created/updated or deleted.
+ */
+public class FactoryConfigurationAdapterImpl extends AbstractDecorator 
implements ManagedServiceFactory
+{
+    // The Adapter Service (we need to inherit all its dependencies).
+    private volatile Service m_service;
+
+    // Our injected dependency manager (we will register CM configuration as 
DM services)
+    protected volatile DependencyManager m_dm;
+    
+    // Our adapter implementation (either a Class, or an Object instance)
+    private final Object m_adapterImplementation;
+
+    // Our adapter interface(s) (either null, a String, or a String array)
+    private final Object m_adapterInterface;
+    
+    // Our adapter service properties (may be null)
+    private final Dictionary m_adapterProperties;
+    
+    // Our Managed Service Factory PID
+    private String m_factoryPid;
+    
+    // The adapter "update" method used to provide the configuration
+    private String m_update;
+
+    // Tells if the CM config must be propagated along with the adapter 
service properties
+    private boolean m_propagate;
+    
+    /**
+     * Creates a new CM factory configuration adapter.
+     * 
+     * @param factoryPid
+     * @param updateMethod
+     * @param adapterInterface
+     * @param adapterImplementation
+     * @param adapterProperties
+     * @param propagate
+     */
+    public FactoryConfigurationAdapterImpl(String factoryPid, String 
updateMethod, Object adapterImplementation, Object adapterInterface, Dictionary 
adapterProperties, boolean propagate)
+    {
+        m_factoryPid = factoryPid;
+        m_update = updateMethod;
+        m_adapterImplementation = adapterImplementation;
+        m_adapterInterface = adapterInterface;
+        m_adapterProperties = adapterProperties;
+        m_propagate = propagate;
+    }
+
+    /**
+     * Returns the managed service factory name.
+     */
+    public String getName()
+    {
+        return m_factoryPid;
+    }
+  
+    /**
+     * Method called from our superclass, when we need to create a service.
+     */
+    public Service createService(Object[] properties) {
+        Dictionary settings = (Dictionary) properties[0];     
+        Service newService = m_dm.createService();        
+        Object impl;
+        
+        try {
+            impl = (m_adapterImplementation instanceof Class) ? 
+                ((Class) m_adapterImplementation).newInstance() : 
m_adapterImplementation;
+            InvocationUtil.invokeCallbackMethod(impl, m_update, 
+                new Class[][] {{ Dictionary.class }, {}}, 
+                new Object[][] {{ settings }, {}});
+        }
+        
+        catch (InvocationTargetException e)
+        {
+            // Our super class will check if the target exception is itself a 
ConfigurationException.
+            // In this case, it will simply re-thrown.
+            throw new RuntimeException(e.getTargetException());
+        }
+        
+        catch (Throwable t) {
+            if (t instanceof RuntimeException) {
+                throw (RuntimeException) t;
+            } else {
+                throw new RuntimeException(t);
+            }
+        }
+
+        // Merge adapter service properties, with CM settings 
+        Dictionary serviceProperties = m_propagate ? 
mergeSettings(m_adapterProperties, settings) : m_adapterProperties;
+   
+        if (m_adapterInterface instanceof String)
+        {
+            newService.setInterface((String) m_adapterInterface, 
serviceProperties);
+        }
+        else if (m_adapterInterface instanceof String[])
+        {
+            newService.setInterface((String[]) m_adapterInterface, 
serviceProperties);
+        }
+
+        newService.setImplementation(impl);
+        List dependencies = m_service.getDependencies();
+        newService.add(dependencies);
+        return newService;
+    }
+
+    /**
+     * Method called from our superclass, when we need to update a Service, 
because 
+     * the configuration has changed.
+     */
+    public void updateService(Object[] properties) 
+    {
+        Dictionary settings = (Dictionary) properties[0];
+        Service service = (Service) properties[1];
+        Object impl = service.getService();
+       
+        try
+        {
+            InvocationUtil.invokeCallbackMethod(impl, m_update, 
+                new Class[][] {{ Dictionary.class }, {}}, 
+                new Object[][] {{ settings }, {}});
+            if (m_adapterInterface != null && m_propagate == true) {
+                settings = mergeSettings(m_adapterProperties, settings);
+                service.setServiceProperties(settings);
+            }
+        }
+        
+        catch (InvocationTargetException e)
+        {
+            // Our super class will check if the target exception is itself a 
ConfigurationException.
+            // In this case, it will simply re-thrown.
+            throw new RuntimeException(e.getTargetException());
+        }
+        
+        catch (Throwable t) {
+            if (t instanceof RuntimeException) {
+                throw (RuntimeException) t;
+            } else {
+                throw new RuntimeException(t);
+            }
+        }
+    }   
+
+    /**
+     * Merge CM factory configuration setting with the adapter service 
properties. The private CM factory configuration 
+     * settings are ignored. A CM factory configuration property is private if 
its name starts with a dot (".").
+     * 
+     * @param adapterProperties
+     * @param settings
+     * @return
+     */
+    private Dictionary mergeSettings(Dictionary adapterProperties, Dictionary 
settings)
+    {
+        Dictionary props = new Hashtable();
+        
+        if (adapterProperties != null) {
+            Enumeration keys = adapterProperties.keys();
+            while (keys.hasMoreElements()) {
+                Object key = keys.nextElement();
+                Object val = adapterProperties.get(key);
+                props.put(key, val);
+            }
+        }
+        
+        Enumeration keys = settings.keys();
+        while (keys.hasMoreElements()) {
+            Object key = keys.nextElement();
+            if (! key.toString().startsWith(".")) {
+                // public properties are propagated
+                Object val = settings.get(key);
+                props.put(key, val);
+            }
+        }
+        return props;
+    }
+}

Added: 
felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java?rev=935222&view=auto
==============================================================================
--- 
felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
 (added)
+++ 
felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
 Sat Apr 17 18:23:35 2010
@@ -0,0 +1,240 @@
+/*
+ * 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;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.service.Service;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+...@runwith(JUnit4TestRunner.class)
+public class FactoryConfigurationAdapterTest extends Base
+{
+    private static Ensure m_ensure;
+    
+    @Configuration
+    public static Option[] configuration() {
+        return options(
+            provision(
+                
mavenBundle().groupId("org.osgi").artifactId("org.osgi.compendium").version("4.1.0"),
+                
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.configadmin").version("1.2.4"),
+                
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.dependencymanager").versionAsInProject()
+            )
+        );
+    }    
+    
+    @Test
+    public void testFactoryConfigurationAdapter(BundleContext context) {
+        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");
+        Service s1 = m.createService()
+            .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.
+        Service s2 = 
m.createFactoryConfigurationAdapterService("MyFactoryPid", 
+                                                                 "updated", 
+                                                                 
Adapter.class, 
+                                                                 
AdapterService.class.getName(), 
+                                                                 new 
Properties() {{ put("foo", "bar"); }},
+                                                                 true /* 
propagate CM settings */);
+        s2.add(m.createServiceDependency()
+            .setService(AdapterExtraDependency.class)
+            .setRequired(true)
+            .setAutoConfig(true));
+        
+        // Create extra adapter service dependency which our adapter depends 
on.
+        Service s3 = m.createService()
+            .setImplementation(new AdapterExtraDependency())
+            .setInterface(AdapterExtraDependency.class.getName(), null);
+        
+        // Create an AdapterService Consumer
+        Service s4 = m.createService()
+            .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);
+    }
+
+    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);
+                Properties props = new Properties();
+                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) {
+            Properties props = new Properties();
+            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 {
+        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);
+            }
+        }
+
+        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);
+        }
+    }
+}
\ No newline at end of file


Reply via email to