ConfigAdmin factory configuration adapter support
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@935222 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
index 359996d..75287bc 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
@@ -186,6 +186,46 @@
}
/**
+ * 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
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
index 7b91dd3..961e240 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
@@ -21,6 +21,7 @@
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.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.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 @@
}
/**
+ * 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
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
index 7cf3478..40fe7cd 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
@@ -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.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 @@
m_manager.remove((Service) i.next());
}
m_services.clear();
- }
+ }
}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
new file mode 100644
index 0000000..f08f4ae
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
@@ -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;
+ }
+}
diff --git a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
new file mode 100644
index 0000000..92acd27
--- /dev/null
+++ b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
@@ -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