You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2014/03/18 22:47:17 UTC
svn commit: r1579067 -
/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/
Author: pderop
Date: Tue Mar 18 21:47:17 2014
New Revision: 1579067
URL: http://svn.apache.org/r1579067
Log:
added bundle dependency, bundle adapter, resource dependency, resource adapter, timed service dependency tests
Added:
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleAdapterTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleDependencyTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FELIX2348_ResourceAdapterTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FactoryConfigurationAdapterTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FilterIndexResourceAdapterTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ModifiedBundleDependencyTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest2.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceDependencyTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ServiceUpdateTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleAdapterTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleAdapterTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,72 @@
+package dm.it;
+
+import junit.framework.Assert;
+
+import org.osgi.framework.Bundle;
+
+import dm.Component;
+import dm.DependencyManager;
+
+// TODO add more tests
+public class BundleAdapterTest extends TestBase {
+ private final static String BSN = "org.apache.felix.metatype";
+
+ public void testBundleAdapter() {
+ DependencyManager m = new DependencyManager(context);
+ // create a bundle adapter service (one is created for each bundle)
+ Component adapter = m.createBundleAdapterService(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE, null, false)
+ .setImplementation(BundleAdapter.class)
+ .setInterface(BundleAdapter.class.getName(), null);
+
+ // create a service provider and consumer
+ Consumer c = new Consumer();
+ Component consumer = m.createComponent().setImplementation(c)
+ .add(m.createServiceDependency().setService(BundleAdapter.class).setCallbacks("add", "remove"));
+
+ // add the bundle adapter
+ m.add(adapter);
+ // add the service consumer
+ m.add(consumer);
+ // check if at least one bundle was found
+ c.check();
+ // remove the consumer again
+ m.remove(consumer);
+ // check if all bundles were removed correctly
+ c.doubleCheck();
+ // remove the bundle adapter
+ m.remove(adapter);
+ }
+
+ public static class BundleAdapter {
+ volatile Bundle m_bundle;
+
+ Bundle getBundle() {
+ return m_bundle;
+ }
+ }
+
+ static class Consumer {
+ private volatile int m_count = 0;
+
+ public void add(BundleAdapter ba) {
+ Bundle b = ba.getBundle();
+ System.out.println("Consumer.add(" + b.getSymbolicName() + ")");
+ Assert.assertNotNull("bundle instance must not be null", b);
+ m_count++;
+ }
+
+ public void check() {
+ Assert.assertTrue("we should have found at least one bundle", m_count > 0);
+ }
+
+ public void remove(BundleAdapter ba) {
+ Bundle b = ba.getBundle();
+ System.out.println("Consumer.remove(" + b.getSymbolicName() + ")");
+ m_count--;
+ }
+
+ public void doubleCheck() {
+ Assert.assertEquals("all bundles we found should have been removed again", 0, m_count);
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleDependencyTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/BundleDependencyTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,121 @@
+package dm.it;
+
+import junit.framework.Assert;
+
+import org.osgi.framework.Bundle;
+
+import dm.Component;
+import dm.DependencyManager;
+
+public class BundleDependencyTest extends TestBase {
+ private final static String BSN = "org.apache.felix.metatype";
+
+ public void testBundleDependencies() {
+ DependencyManager m = new DependencyManager(context);
+ // create a service provider and consumer
+ Consumer c = new Consumer();
+ Component consumer = m.createComponent().setImplementation(c).add(m.createBundleDependency().setCallbacks("add", "remove"));
+ // add the service consumer
+ m.add(consumer);
+ // check if at least one bundle was found
+ c.check();
+ // remove the consumer again
+ m.remove(consumer);
+ // check if all bundles were removed correctly
+ c.doubleCheck();
+
+ // helper class that ensures certain steps get executed in sequence
+ Ensure e = new Ensure();
+ Component consumerWithFilter = m.createComponent().setImplementation(new FilteredConsumer(e)).add(m.createBundleDependency().setFilter("(Bundle-SymbolicName=" + BSN + ")").setCallbacks("add", "remove"));
+ // add a consumer with a filter
+ m.add(consumerWithFilter);
+ e.step(2);
+ // remove the consumer again
+ m.remove(consumerWithFilter);
+ e.step(4);
+ }
+
+ public void testRequiredBundleDependency() {
+ DependencyManager m = new DependencyManager(context);
+ // create a service provider and consumer
+ Consumer c = new Consumer();
+
+ // helper class that ensures certain steps get executed in sequence
+ Ensure e = new Ensure();
+ Component consumerWithFilter = m.createComponent()
+ .setImplementation(new FilteredConsumerRequired(e))
+ .add(m.createBundleDependency()
+ .setRequired(true)
+ .setFilter("(Bundle-SymbolicName=" + BSN + ")")
+ .setCallbacks("add", "remove")
+ );
+ // add a consumer with a filter
+ m.add(consumerWithFilter);
+ e.waitForStep(1, 5000);
+ // remove the consumer again
+ m.remove(consumerWithFilter);
+ e.waitForStep(2, 5000);
+ }
+
+ static class Consumer {
+ private volatile int m_count = 0;
+
+ public void add(Bundle b) {
+ System.out.println("Consumer.add(" + b.getSymbolicName() + ")");
+ Assert.assertNotNull("bundle instance must not be null", b);
+ m_count++;
+ }
+
+ public void check() {
+ Assert.assertTrue("we should have found at least one bundle", m_count > 0);
+ }
+
+ public void remove(Bundle b) {
+ System.out.println("Consumer.remove(" + b.getSymbolicName() + ")");
+ m_count--;
+ }
+
+ public void doubleCheck() {
+ Assert.assertEquals("all bundles we found should have been removed again", 0, m_count);
+ }
+ }
+
+ static class FilteredConsumer {
+ private final Ensure m_ensure;
+
+ public FilteredConsumer(Ensure e) {
+ m_ensure = e;
+ }
+
+ public void add(Bundle b) {
+ m_ensure.step(1);
+ }
+
+ public void remove(Bundle b) {
+ m_ensure.step(3);
+ }
+ }
+
+ static class FilteredConsumerRequired {
+ private final Ensure m_ensure;
+
+ public FilteredConsumerRequired(Ensure e) {
+ m_ensure = e;
+ }
+
+ public void add(Bundle b) {
+ System.out.println("Bundle is " + b);
+// Assert.assertNotNull(b);
+ if (b.getSymbolicName().equals(BSN)) {
+ m_ensure.step(1);
+ }
+ }
+
+ public void remove(Bundle b) {
+ Assert.assertNotNull(b);
+ if (b.getSymbolicName().equals(BSN)) {
+ m_ensure.step(2);
+ }
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FELIX2348_ResourceAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FELIX2348_ResourceAdapterTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FELIX2348_ResourceAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FELIX2348_ResourceAdapterTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,122 @@
+package dm.it;
+
+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.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import dm.DependencyManager;
+import dm.ResourceHandler;
+import dm.ResourceUtil;
+
+public class FELIX2348_ResourceAdapterTest extends TestBase {
+ public void testBasicResourceAdapter() throws Exception {
+ DependencyManager m = new DependencyManager(context);
+ // helper class that ensures certain steps get executed in sequence
+ Ensure e = new Ensure();
+ m.add(m.createResourceAdapterService("(&(path=/path/to/*.txt)(host=localhost))", false, null, "changed")
+ .setImplementation(new ResourceAdapter(e)));
+ m.add(m.createComponent().setImplementation(new ResourceProvider(e)).add(m.createServiceDependency().setService(ResourceHandler.class).setCallbacks("add", "remove")));
+ e.waitForStep(3, 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.");
+ }
+ }
+ }
+
+ 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 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());
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FactoryConfigurationAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FactoryConfigurationAdapterTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FactoryConfigurationAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FactoryConfigurationAdapterTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,202 @@
+package dm.it;
+
+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.osgi.service.cm.ConfigurationAdmin;
+
+import dm.Component;
+import dm.DependencyManager;
+
+public class FactoryConfigurationAdapterTest extends TestBase
+{
+ private static Ensure m_ensure;
+
+ 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.createAdapterFactoryConfigurationService("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-prototype/dm.it/src/dm/it/FilterIndexResourceAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FilterIndexResourceAdapterTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FilterIndexResourceAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/FilterIndexResourceAdapterTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,155 @@
+package dm.it;
+
+//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.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import dm.DependencyManager;
+import dm.ResourceHandler;
+import dm.ResourceUtil;
+
+public class FilterIndexResourceAdapterTest extends TestBase {
+ 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-prototype/dm.it/src/dm/it/ModifiedBundleDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ModifiedBundleDependencyTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ModifiedBundleDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ModifiedBundleDependencyTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,121 @@
+package dm.it;
+
+import junit.framework.Assert;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+import dm.Component;
+import dm.DependencyManager;
+
+/**
+ * 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>
+ */
+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).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);
+ }
+ }
+
+ 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.metatype)")
+ .setStateMask(Bundle.INSTALLED|Bundle.ACTIVE|Bundle.RESOLVED|Bundle.STARTING)
+ .setRequired(true)
+ .setCallbacks("add", "change", "remove"));
+
+ Bundle dmtest = getBundle("org.apache.felix.metatype");
+ try {
+ dmtest.stop();
+ } catch (BundleException e1) {
+ Assert.fail("could not find metatype 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 metatype bundle ...");
+ try {
+ dmtest.start();
+ } catch (BundleException e1) {
+ Assert.fail("could not start metatype bundle");
+ }
+ e.waitForStep(7, 5000);
+ m.remove(b);
+ e.waitForStep(10, 5000);
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,245 @@
+package dm.it;
+
+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.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import dm.Component;
+import dm.ComponentState;
+import dm.ComponentStateListener;
+import dm.Dependency;
+import dm.DependencyManager;
+import dm.ResourceHandler;
+import dm.ResourceUtil;
+
+public class ResourceAdapterDependencyAddAndRemoveTest extends TestBase {
+ 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
+
+ Dependency d = m.createServiceDependency()
+ .setService(ServiceInterface.class)
+ .setRequired(true);
+ CallbackInstance callbackInstance = new CallbackInstance(e, d);
+ Component component = m.createResourceAdapterService("(&(path=/path/to/*.txt)(host=localhost))", false, callbackInstance, "changed")
+ .setImplementation(new ResourceAdapter(e, d))
+ .setCallbacks(callbackInstance, "init", "start", "stop", "destroy");
+
+ // 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
+ // add a component state listener, in order to track resource adapter destruction
+ component.add(new ComponentStateListenerImpl(e));
+ m.remove(component);
+
+ // wait for the stopped callback in the state listener
+ e.waitForStep(4, 5000);
+ m.clear();
+ }
+
+ static class ResourceAdapter {
+ protected URL m_resource; // injected by reflection.
+ private Ensure m_ensure;
+ private final Dependency m_dependency;
+
+ ResourceAdapter(Ensure e, Dependency d) {
+ m_ensure = e;
+ m_dependency = d;
+ }
+
+ void init(Component c) {
+ c.add(m_dependency);
+ }
+ }
+
+ 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) {
+ debug("ResourceProvider.add(ref=%s, handler=%s", ref, 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) {
+ debug("ResourceProvider.remove: ref=%s, handler=%s, handlers=%s", ref, handler, 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() {
+ debug("ResourceProvider:%s", m_handlers);
+ Entry[] handlers;
+ synchronized (m_handlers) {
+ debug("ResourceProvider.destroy: handlers=%s", 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());
+ }
+
+ debug("DESTROY...%d", 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() {
+ }
+ }
+
+ class CallbackInstance {
+ private final Dependency m_dependency;
+ private final Ensure m_ensure;
+
+
+ public CallbackInstance(Ensure e, Dependency d) {
+ m_ensure = e;
+ m_dependency = d;
+ }
+
+ void init() {
+ debug("CallbackInstance.init");
+ }
+
+ void start() {
+ debug("CallbackInstance.start");
+ m_ensure.step(1);
+ }
+
+ void stop() {
+ debug("CallbackInstance.stop");
+ }
+
+ void destroy() {
+ debug("CallbackInstance.destroy");
+ }
+
+ void changed(Component component) {
+ m_ensure.step(2);
+ Dependency oldDependency = m_dependency;
+ // and add a new dependency
+ component.add(component.getDependencyManager().createServiceDependency().setService(ServiceInterface.class).setRequired(true));
+ // remove the old dependency
+ component.remove(oldDependency);
+ debug("CallbackInstance.changed the dependencies");
+ m_ensure.step(3);
+ }
+ }
+
+ class ComponentStateListenerImpl implements ComponentStateListener {
+
+ private final Ensure m_ensure;
+
+ public ComponentStateListenerImpl(Ensure e) {
+ this.m_ensure = e;
+ }
+
+ public void changed(ComponentState state) {
+ debug("ComponentStateListenerImpl.changed: state=%s", state);
+ switch (state) {
+ case INACTIVE:
+ System.out.println("stopped");
+ m_ensure.step(4);
+ }
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest2.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest2.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest2.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterDependencyAddAndRemoveTest2.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,247 @@
+package dm.it;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import dm.Component;
+import dm.ComponentState;
+import dm.ComponentStateListener;
+import dm.Dependency;
+import dm.DependencyManager;
+import dm.ResourceHandler;
+import dm.ResourceUtil;
+
+public class ResourceAdapterDependencyAddAndRemoveTest2 extends TestBase {
+ 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 a resource provider
+ ResourceProvider provider = new ResourceProvider(e);
+ // activate it
+ Properties props = new Properties();
+ props.setProperty("id", "1");
+ m.add(m.createComponent()
+ .setInterface(ServiceInterface.class.getName(), props)
+ .setImplementation(new ServiceProvider(e))
+ );
+
+ props = new Properties();
+ props.setProperty("id", "2");
+ m.add(m.createComponent()
+ .setInterface(ServiceInterface.class.getName(), props)
+ .setImplementation(new ServiceProvider(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
+ Dependency d = m.createServiceDependency().setService(ServiceInterface.class, "(id=1)").setRequired(true);
+ ResourceAdapter service = new ResourceAdapter(e, d);
+
+ CallbackInstance callbackInstance = new CallbackInstance(e, d);
+ Component component = m.createResourceAdapterService("(&(path=/path/to/*.txt)(host=localhost))", false, callbackInstance, "changed")
+ .setImplementation(service)
+ .setCallbacks(callbackInstance, "init", "start", "stop", "destroy");
+ component.add(new ComponentStateListenerImpl(e));
+ m.add(component);
+ // wait until the single resource is available
+ e.waitForStep(1, 5000);
+ // trigger a 'change' in our resource
+ provider.change();
+ // wait until the changed callback is invoked
+ e.waitForStep(2, 5000);
+
+ System.out.println("Done!");
+ m.clear();
+ }
+
+ static class ResourceAdapter {
+ protected URL m_resource; // injected by reflection.
+ private Ensure m_ensure;
+ final Dependency m_dependency;
+
+ ResourceAdapter(Ensure e, Dependency d) {
+ m_ensure = e;
+ m_dependency = d;
+ }
+
+ void init(Component c) {
+ c.add(m_dependency);
+ }
+ }
+
+ 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());
+ }
+ }
+ }
+
+ 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;
+ private final Dependency m_dependency;
+
+ public CallbackInstance(Ensure e, Dependency d) {
+ m_ensure = e;
+ m_dependency = d;
+ }
+
+ void init() {
+ System.out.println("init");
+ m_ensure.step(1);
+ }
+
+ void start() {
+ System.out.println("start");
+ }
+
+ void stop() {
+ System.out.println("stop");
+ }
+
+ void destroy() {
+ System.out.println("destroy");
+ }
+
+ void changed(Component component) {
+ m_ensure.step(2);
+ System.out.println("Changing the dependencies");
+ Dependency oldDependency = m_dependency;
+
+ // and add a new dependency
+ component.add(component.getDependencyManager().createServiceDependency().setService(ServiceInterface.class, "(id=2)").setRequired(true));
+ // remove the old dependency
+ component.remove(oldDependency);
+ System.out.println("Changed the dependencies");
+ }
+ }
+
+ static class ComponentStateListenerImpl implements ComponentStateListener {
+ private final Ensure m_ensure;
+
+ public ComponentStateListenerImpl(Ensure e) {
+ this.m_ensure = e;
+ }
+
+ @Override
+ public void changed(ComponentState state) {
+ switch (state) {
+ case INACTIVE:
+ System.out.println("INACTIVE");
+ break;
+ case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+ System.out.println("INSTANTIATED_AND_WAITING_FOR_REQUIRED");
+ break;
+ case WAITING_FOR_REQUIRED:
+ System.out.println("WAITING_FOR_REQUIRED");
+ break;
+ case TRACKING_OPTIONAL:
+ System.out.println("TRACKING_OPTIONAL");
+ break;
+
+ }
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceAdapterTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,150 @@
+package dm.it;
+
+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.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import dm.DependencyManager;
+import dm.ResourceHandler;
+import dm.ResourceUtil;
+
+public class ResourceAdapterTest extends TestBase {
+ 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 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) {
+ 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-prototype/dm.it/src/dm/it/ResourceDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceDependencyTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ResourceDependencyTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,215 @@
+package dm.it;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+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.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import dm.Component;
+import dm.DependencyManager;
+import dm.ResourceHandler;
+import dm.ResourceUtil;
+
+public class ResourceDependencyTest extends TestBase {
+ public void testResourceDependency() {
+ 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
+ ResourceConsumer c = new ResourceConsumer(e);
+ Component consumer = m.createComponent()
+ .setImplementation(c)
+ .add(m.createResourceDependency()
+ .setFilter("(&(path=/path/to/*.txt)(host=localhost))")
+ .setCallbacks("add", "change", "remove"));
+ Component dynamicProxyConsumer = m.createComponent()
+ .setFactory(new ResourceConsumerFactory(e), "create")
+ .add(m.createResourceDependency()
+ .setFilter("(path=*.doc)")
+ .setCallbacks("add", null));
+ ResourceProvider provider = new ResourceProvider(e);
+ Component resourceProvider = m.createComponent()
+ .setImplementation(provider)
+ .add(m.createServiceDependency()
+ .setService(ResourceHandler.class)
+ .setCallbacks("add", "remove"));
+
+ // first add the consumer
+ m.add(consumer);
+ // then the resource provider, which will provide 3 resources,
+ // 2 of which match the consumers filter conditions
+ m.add(resourceProvider);
+ // make sure our consumer invoked openStream() on both resources,
+ // increasing the step counter to 2
+ e.step(3);
+
+ // now add another consumer, that matches only one resource, and uses
+ // a dynamic proxy as its implementation
+ m.add(dynamicProxyConsumer);
+ // ensure the resource was injected properly
+ e.waitForStep(4, 5000);
+
+ // now change a resource and see if it gets propagated to the consumer
+ provider.changeResource();
+
+ // wait for change callback
+ e.waitForStep(5, 5000);
+ e.step(6);
+
+ // cleanup
+ m.remove(dynamicProxyConsumer);
+ m.remove(resourceProvider);
+ m.remove(consumer);
+
+ // validate that all consumed resources are "unconsumed" again
+ c.ensure();
+ }
+
+ class ResourceConsumer {
+ private volatile int m_counter;
+ private Ensure m_ensure;
+
+ public ResourceConsumer(Ensure ensure) {
+ m_ensure = ensure;
+ }
+
+ public void add(URL resource) {
+ debug("ResourceConsumer.add(%s)", resource);
+ m_counter++;
+ m_ensure.step();
+ }
+ public void change(URL resource) {
+ m_ensure.step();
+ }
+ public void remove(URL resource) {
+ debug("ResourceConsumer.remove(%s)", resource);
+ m_counter--;
+ }
+ public void ensure() {
+ Assert.assertTrue("all resources should have been added and removed at this point, but " + m_counter + " are remaining", m_counter == 0);
+ }
+ }
+
+ class ResourceProvider {
+ private volatile BundleContext m_context;
+ private final Ensure m_ensure;
+ private final Map<ResourceHandler, Filter> m_handlers = new HashMap<ResourceHandler, Filter>();
+ private URL[] m_resources;
+
+ public ResourceProvider(Ensure ensure) {
+ m_ensure = ensure;
+ try {
+ m_resources = new URL[] {
+ new URL("file://localhost/path/to/file1.txt"),
+ new URL("file://localhost/path/to/file2.txt"),
+ new URL("file://localhost/path/to/file3.doc")
+ };
+ }
+ catch (MalformedURLException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public void add(ServiceReference ref, ResourceHandler handler) {
+ String filterString = (String) ref.getProperty("filter");
+ Filter filter;
+ 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.match(ResourceUtil.createProperties(m_resources[i]))) {
+ handler.added(m_resources[i]);
+ }
+ }
+ }
+
+ public void changeResource() {
+ Filter filter;
+ for (Entry<ResourceHandler, Filter> entry : m_handlers.entrySet()) {
+ for (int i = 0; i < m_resources.length; i++) {
+ if (i == 0) {
+ if (entry.getValue().match(ResourceUtil.createProperties(m_resources[i]))) {
+ entry.getKey().changed(m_resources[i]);
+ }
+ }
+ }
+ }
+ }
+
+ public void remove(ServiceReference ref, ResourceHandler handler) {
+ debug("ResourceProvider.remove(ref=%s, handler=%s, handlers=%s", ref, handler, m_handlers);
+ 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.match(ResourceUtil.createProperties(m_resources[i]))) {
+ handler.removed(m_resources[i]);
+ }
+ }
+ }
+
+ public void destroy() {
+ debug("ResourceProvider.destroy: handlers=%s", m_handlers);
+ 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());
+ }
+ }
+ }
+
+ class ResourceConsumerFactory {
+ private final Ensure m_ensure;
+ public ResourceConsumerFactory(Ensure ensure) {
+ m_ensure = ensure;
+ }
+ public Object create() {
+ ResourceConsumer resourceConsumer = new ResourceConsumer(m_ensure);
+ // create a dynamic proxy for the ResourceProvider
+ return Proxy.newProxyInstance(resourceConsumer.getClass().getClassLoader(), resourceConsumer.getClass().getInterfaces(), new DynamicProxyHandler(resourceConsumer, m_ensure));
+ }
+ }
+
+ static class DynamicProxyHandler implements InvocationHandler {
+ Ensure m_ensure;
+ ResourceConsumer resourceConsumer = null;
+
+ public DynamicProxyHandler(ResourceConsumer resourceConsumer, Ensure ensure) {
+ this.resourceConsumer = resourceConsumer;
+ m_ensure = ensure;
+ }
+
+ public void add(URL resource) {
+ m_ensure.step(4);
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return method.invoke(resourceConsumer, args);
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ServiceUpdateTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ServiceUpdateTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ServiceUpdateTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/ServiceUpdateTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,220 @@
+package dm.it;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import dm.Component;
+import dm.DependencyManager;
+import dm.ResourceHandler;
+import dm.ResourceUtil;
+
+public class ServiceUpdateTest extends TestBase {
+ public void testServiceUpdate() throws Exception {
+ 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(new ServiceProvider(e))
+ .add(m.createServiceDependency()
+ .setService(ServiceInterface.class)
+ .setRequired(true)
+ .setCallbacks("add", "change", "remove")
+ )
+ );
+
+ 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
+ CallbackInstance callbackInstance = new CallbackInstance(e);
+ Properties serviceProps = new Properties();
+ serviceProps.setProperty("number", "1");
+ Component component = m.createResourceAdapterService("(&(path=/path/to/*.txt)(host=localhost))", false, callbackInstance, "changed")
+ .setImplementation(new ResourceAdapter(e))
+ .setInterface(ServiceInterface.class.getName(), serviceProps)
+ .setCallbacks(callbackInstance, "init", "start", "stop", "destroy");
+ m.add(component);
+ // wait until the single resource is available
+ e.waitForStep(1, 5000);
+ // wait until the component gets the dependency injected
+ e.waitForStep(2, 5000);
+ // trigger a 'change' in our resource
+ provider.change();
+ // wait until the changed callback is invoked
+ e.waitForStep(3, 5000);
+ // wait until the changed event arrived at the component
+ e.waitForStep(4, 5000);
+ System.out.println("Done!");
+ m.clear();
+ }
+
+ static class ResourceAdapter implements ServiceInterface {
+ protected URL m_resource; // injected by reflection.
+ private Ensure m_ensure;
+
+ ResourceAdapter(Ensure e) {
+ m_ensure = e;
+ }
+
+ public void invoke() {
+ // TODO Auto-generated method stub
+
+ }
+ }
+
+ 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());
+ }
+ }
+ }
+
+ static interface ServiceInterface {
+ public void invoke();
+ }
+
+ static class ServiceProvider {
+ private final Ensure m_ensure;
+ public ServiceProvider(Ensure e) {
+ m_ensure = e;
+ }
+ void add(ServiceInterface i) {
+ m_ensure.step(2);
+ }
+ void change(ServiceInterface i) {
+ System.out.println("Change...");
+ m_ensure.step(4);
+ }
+ void remove(ServiceInterface i) {
+ System.out.println("Remove...");
+ }
+ }
+
+ 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) {
+ System.out.println("resource changed");
+ m_ensure.step(3);
+
+ Properties newProps = new Properties();
+ // update the component's service properties
+ Dictionary dict = component.getServiceProperties();
+ Enumeration e = dict.keys();
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+ String value = (String) dict.get(key);
+ newProps.setProperty(key, value);
+ }
+ newProps.setProperty("new-property", "2");
+ component.getServiceRegistration().setProperties(newProps);
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java?rev=1579067&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java Tue Mar 18 21:47:17 2014
@@ -0,0 +1,82 @@
+package dm.it;
+
+import dm.Component;
+import dm.DependencyManager;
+
+public class TemporalServiceDependencyTest extends TestBase {
+ public void testServiceConsumptionAndIntermittentAvailability() {
+ 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 sp = m.createComponent().setImplementation(new TemporalServiceProvider(e)).setInterface(TemporalServiceInterface.class.getName(), null);
+ Component sp2 = m.createComponent().setImplementation(new TemporalServiceProvider2(e)).setInterface(TemporalServiceInterface.class.getName(), null);
+ Component sc = m.createComponent().setImplementation(new TemporalServiceConsumer(e)).add(m.createTemporalServiceDependency().setService(TemporalServiceInterface.class).setRequired(true));
+ // add the service consumer
+ m.add(sc);
+ // now add the first provider
+ m.add(sp);
+ e.waitForStep(2, 15000);
+ // and remove it again (this should not affect the consumer yet)
+ m.remove(sp);
+ // now add the second provider
+ m.add(sp2);
+ e.step(3);
+ e.waitForStep(4, 15000);
+ // and remove it again
+ m.remove(sp2);
+ // finally remove the consumer
+ m.remove(sc);
+ // ensure we executed all steps inside the component instance
+ e.step(6);
+ }
+
+ static interface TemporalServiceInterface {
+ public void invoke();
+ }
+
+ static class TemporalServiceProvider implements TemporalServiceInterface {
+ private final Ensure m_ensure;
+ public TemporalServiceProvider(Ensure e) {
+ m_ensure = e;
+ }
+ public void invoke() {
+ m_ensure.step(2);
+ }
+ }
+
+ static class TemporalServiceProvider2 implements TemporalServiceInterface {
+ private final Ensure m_ensure;
+ public TemporalServiceProvider2(Ensure e) {
+ m_ensure = e;
+ }
+ public void invoke() {
+ m_ensure.step(4);
+ }
+ }
+
+ static class TemporalServiceConsumer implements Runnable {
+ private volatile TemporalServiceInterface m_service;
+ private final Ensure m_ensure;
+
+ public TemporalServiceConsumer(Ensure e) {
+ m_ensure = e;
+ }
+
+ public void init() {
+ m_ensure.step(1);
+ Thread t = new Thread(this);
+ t.start();
+ }
+
+ public void run() {
+ m_service.invoke();
+ m_ensure.waitForStep(3, 15000);
+ m_service.invoke();
+ }
+
+ public void destroy() {
+ m_ensure.step(5);
+ }
+ }
+}