Author: csierra Date: Mon May 28 14:29:00 2018 New Revision: 1832399 URL: http://svn.apache.org/viewvc?rev=1832399&view=rev Log: [Component-DSL] Get initial configuration state
so configuration is not always set to empty and then initialized asynchronously to the existing value Modified: aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java aries/trunk/component-dsl/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java Modified: aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java URL: http://svn.apache.org/viewvc/aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java?rev=1832399&r1=1832398&r2=1832399&view=diff ============================================================================== --- aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java (original) +++ aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java Mon May 28 14:29:00 2018 @@ -17,11 +17,18 @@ package org.apache.aries.component.dsl.internal; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; -import org.osgi.service.cm.ManagedService; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.cm.ConfigurationEvent; +import org.osgi.service.cm.ConfigurationListener; import java.util.Dictionary; import java.util.Hashtable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -32,7 +39,7 @@ public class ConfigurationOSGiImpl exten public ConfigurationOSGiImpl(String pid) { super((bundleContext, op) -> { - AtomicReference<Dictionary<String, ?>> atomicReference = + AtomicReference<Configuration> atomicReference = new AtomicReference<>(null); AtomicReference<Runnable> @@ -40,17 +47,55 @@ public class ConfigurationOSGiImpl exten AtomicBoolean closed = new AtomicBoolean(); - ServiceRegistration<ManagedService> serviceRegistration = + CountDownLatch countDownLatch = new CountDownLatch(1); + + ServiceRegistration<?> serviceRegistration = bundleContext.registerService( - ManagedService.class, - properties -> { - atomicReference.set(properties); + ConfigurationListener.class, + (ConfigurationEvent configurationEvent) -> { + if (configurationEvent.getFactoryPid() != null || + !configurationEvent.getPid().equals(pid)) { + + return; + } + + try { + countDownLatch.await(1, TimeUnit.MINUTES); + } + catch (InterruptedException e) { + return; + } + + Configuration configuration; + + if (configurationEvent.getType() == + ConfigurationEvent.CM_DELETED) { - signalLeave(terminatorAtomicReference); + atomicReference.set(null); - if (properties != null) { + signalLeave(terminatorAtomicReference); + } + else { + configuration = getConfiguration( + bundleContext, configurationEvent); + + if (configuration == null) { + return; + } + + Configuration old = atomicReference.get(); + + if (old == null || + configuration.getChangeCount() != + old.getChangeCount()) { + + atomicReference.set(configuration); + } + + signalLeave(terminatorAtomicReference); + terminatorAtomicReference.set( - op.apply(properties)); + op.apply(configuration.getProperties())); if (closed.get()) { /* @@ -59,14 +104,27 @@ public class ConfigurationOSGiImpl exten directly instead of storing it */ signalLeave(terminatorAtomicReference); - - return; } } }, - new Hashtable<String, Object>() {{ - put("service.pid", pid); - }}); + new Hashtable<>()); + + ServiceReference<ConfigurationAdmin> serviceReference = + bundleContext.getServiceReference(ConfigurationAdmin.class); + + if (serviceReference != null) { + Configuration configuration = getConfiguration( + bundleContext, pid, serviceReference); + + if (configuration != null) { + atomicReference.set(configuration); + + terminatorAtomicReference.set( + op.apply(configuration.getProperties())); + } + } + + countDownLatch.countDown(); return new OSGiResultImpl( () -> { @@ -79,6 +137,43 @@ public class ConfigurationOSGiImpl exten }); } + private static Configuration getConfiguration( + BundleContext bundleContext, ConfigurationEvent configurationEvent) { + + String pid = configurationEvent.getPid(); + + ServiceReference<ConfigurationAdmin> reference = + configurationEvent.getReference(); + + return getConfiguration(bundleContext, pid, reference); + } + + private static Configuration getConfiguration( + BundleContext bundleContext, String pid, + ServiceReference<ConfigurationAdmin> reference) { + + ConfigurationAdmin configurationAdmin = bundleContext.getService( + reference); + + try { + Configuration[] configurations = + configurationAdmin.listConfigurations( + "(&(service.pid=" + pid + ")(!(service.factoryPid=*)))"); + + if (configurations.length == 0) { + return null; + } + + return configurations[0]; + } + catch (Exception e) { + return null; + } + finally { + bundleContext.ungetService(reference); + } + } + private static void signalLeave( AtomicReference<Runnable> terminatorAtomicReference) { Modified: aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java URL: http://svn.apache.org/viewvc/aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java?rev=1832399&r1=1832398&r2=1832399&view=diff ============================================================================== --- aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java (original) +++ aries/trunk/component-dsl/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java Mon May 28 14:29:00 2018 @@ -17,37 +17,123 @@ package org.apache.aries.component.dsl.internal; -import org.apache.aries.component.dsl.Publisher; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; -import org.osgi.service.cm.ConfigurationException; -import org.osgi.service.cm.ManagedServiceFactory; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.cm.ConfigurationEvent; +import org.osgi.service.cm.ConfigurationListener; import java.util.Dictionary; import java.util.Hashtable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; /** * @author Carlos Sierra Andrés */ -public class ConfigurationsOSGiImpl - extends OSGiImpl<Dictionary<String, ?>> { +public class ConfigurationsOSGiImpl extends OSGiImpl<Dictionary<String, ?>> { public ConfigurationsOSGiImpl(String factoryPid) { super((bundleContext, op) -> { - Map<String, Runnable> results = new ConcurrentHashMap<>(); + ConcurrentHashMap<String, Configuration> configurations = + new ConcurrentHashMap<>(); + + ConcurrentHashMap<String, Runnable> terminators = + new ConcurrentHashMap<>(); AtomicBoolean closed = new AtomicBoolean(); - ServiceRegistration<ManagedServiceFactory> serviceRegistration = + CountDownLatch countDownLatch = new CountDownLatch(1); + + ServiceRegistration<?> serviceRegistration = bundleContext.registerService( - ManagedServiceFactory.class, - new ConfigurationsManagedServiceFactory( - results, op, closed), - new Hashtable<String, Object>() {{ - put("service.pid", factoryPid); - }}); + ConfigurationListener.class, + (ConfigurationEvent configurationEvent) -> { + String incomingFactoryPid = + configurationEvent.getFactoryPid(); + + if (incomingFactoryPid == null || + !factoryPid.equals(incomingFactoryPid)) { + + return; + } + + try { + countDownLatch.await(1, TimeUnit.MINUTES); + } + catch (InterruptedException e) { + return; + } + + String pid = configurationEvent.getPid(); + + Configuration configuration; + + if (configurationEvent.getType() == + ConfigurationEvent.CM_DELETED) { + + configurations.remove(pid); + + signalLeave(pid, terminators); + } + else { + configuration = getConfiguration( + bundleContext, configurationEvent); + + Dictionary<String, Object> properties = + configuration.getProperties(); + + configurations.compute( + pid, + (__, old) -> { + if (old == null || + configuration.getChangeCount() != + old.getChangeCount()) { + + return configuration; + } + + return old; + } + ); + + signalLeave(pid, terminators); + + terminators.put(pid, op.apply(properties)); + + if (closed.get()) { + /* + if we have closed while executing the + effects we have to execute the terminator + directly instead of storing it + */ + signalLeave(pid, terminators); + } + } + }, + new Hashtable<>()); + + ServiceReference<ConfigurationAdmin> serviceReference = + bundleContext.getServiceReference(ConfigurationAdmin.class); + + if (serviceReference != null) { + Configuration[] configuration = getConfigurations( + bundleContext, factoryPid, serviceReference); + + for (Configuration c : configuration) { + configurations.put(c.getPid(), c); + + terminators.put(c.getPid(), op.apply(c.getProperties())); + } + } + + countDownLatch.countDown(); return new OSGiResultImpl( () -> { @@ -55,68 +141,88 @@ public class ConfigurationsOSGiImpl serviceRegistration.unregister(); - results.values().forEach(Runnable::run); - - results.clear(); + for (Runnable runnable : terminators.values()) { + if (runnable != null) { + runnable.run(); + } + } }); }); } - private static class ConfigurationsManagedServiceFactory - implements ManagedServiceFactory { + private static Configuration getConfiguration( + BundleContext bundleContext, ConfigurationEvent configurationEvent) { - private final Map<String, Runnable> _results; + String pid = configurationEvent.getPid(); + String factoryPid = configurationEvent.getFactoryPid(); - private final Publisher<? super Dictionary<String, ?>> _op; - private AtomicBoolean _closed; + ServiceReference<ConfigurationAdmin> reference = + configurationEvent.getReference(); - public ConfigurationsManagedServiceFactory( - Map<String, Runnable> results, - Publisher<? super Dictionary<String, ?>> op, - AtomicBoolean closed) { + return getConfiguration(bundleContext, pid, factoryPid, reference); + } - _results = results; - _op = op; - _closed = closed; - } + private static Configuration getConfiguration( + BundleContext bundleContext, String pid, String factoryPid, + ServiceReference<ConfigurationAdmin> reference) { + + ConfigurationAdmin configurationAdmin = bundleContext.getService( + reference); + + try { + Configuration[] configurations = + configurationAdmin.listConfigurations( + "(&(service.pid=" + pid + ")" + + "(service.factoryPid="+ factoryPid + "))"); - @Override - public void deleted(String s) { - Runnable runnable = _results.remove(s); + if (configurations == null || configurations.length == 0) { + return null; + } - runnable.run(); + return configurations[0]; } - - @Override - public String getName() { - return "Functional OSGi Managed Service Factory"; + catch (Exception e) { + return null; + } + finally { + bundleContext.ungetService(reference); } + } - @Override - public void updated(String s, Dictionary<String, ?> dictionary) - throws ConfigurationException { + private static Configuration[] getConfigurations( + BundleContext bundleContext, String factoryPid, + ServiceReference<ConfigurationAdmin> serviceReference) { + + ConfigurationAdmin configurationAdmin = bundleContext.getService( + serviceReference); + + try { + Configuration[] configurations = + configurationAdmin.listConfigurations( + "(&(service.pid=*)(service.factoryPid="+ factoryPid +"))"); - Runnable terminator = _op.apply(dictionary); + if (configurations == null) { + return new Configuration[0]; + } - Runnable old = _results.put(s, terminator); + return configurations; + } + catch (Exception e) { + return new Configuration[0]; + } + finally { + bundleContext.ungetService(serviceReference); + } + } - if (old != null) { - old.run(); - } + private static void signalLeave( + String factoryPid, ConcurrentHashMap<String, Runnable> terminators) { - if (_closed.get()) { - /* if we have been closed while executing the effects we have - to check if this terminator has been left unexecuted. - */ - _results.computeIfPresent( - s, - (key, runnable) -> { - runnable.run(); + Runnable runnable = terminators.remove(factoryPid); - return null; - }); - } + if (runnable != null) { + runnable.run(); } - } + } Modified: aries/trunk/component-dsl/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java URL: http://svn.apache.org/viewvc/aries/trunk/component-dsl/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java?rev=1832399&r1=1832398&r2=1832399&view=diff ============================================================================== --- aries/trunk/component-dsl/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java (original) +++ aries/trunk/component-dsl/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java Mon May 28 14:29:00 2018 @@ -32,7 +32,9 @@ import org.osgi.framework.ServiceRegistr import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedService; import org.osgi.service.cm.ManagedServiceFactory; +import org.osgi.util.tracker.ServiceTracker; import java.io.IOException; import java.util.ArrayList; @@ -390,6 +392,65 @@ public class DSLTest { } @Test + public void testConfigurationWithExistingValues() + throws IOException, InterruptedException { + + ServiceReference<ConfigurationAdmin> serviceReference = + bundleContext.getServiceReference(ConfigurationAdmin.class); + + ConfigurationAdmin configurationAdmin = bundleContext.getService( + serviceReference); + + Configuration configuration = configurationAdmin.getConfiguration( + "test.configuration"); + + configuration.update(new Hashtable<>()); + + AtomicReference<Dictionary<?,?>> atomicReference = + new AtomicReference<>(null); + + AtomicInteger counter = new AtomicInteger(); + + CountDownLatch countDownLatch = new CountDownLatch(2); + + ServiceRegistration<ManagedService> serviceRegistration = + bundleContext.registerService( + ManagedService.class, __ -> countDownLatch.countDown(), + new Hashtable<String, Object>() {{ + put("service.pid", "test.configuration"); + }}); + + try(OSGiResult result = + configuration("test.configuration").run( + bundleContext, + x -> { + atomicReference.set(x); + + counter.incrementAndGet(); + + countDownLatch.countDown(); + + return NOOP; + })) + { + assertNotNull(atomicReference.get()); + + countDownLatch.await(10, TimeUnit.SECONDS); + + assertEquals(1, counter.get()); + } + finally { + bundleContext.ungetService(serviceReference); + + configuration.delete(); + + if (serviceRegistration != null) { + serviceRegistration.unregister(); + } + } + } + + @Test public void testConfigurations() throws IOException, InterruptedException { ServiceReference<ConfigurationAdmin> serviceReference = bundleContext.getServiceReference(ConfigurationAdmin.class); @@ -470,58 +531,34 @@ public class DSLTest { CountDownLatch addedLatch = new CountDownLatch(3); - ServiceRegistration<?> addedServiceRegistration = - bundleContext.registerService( - ManagedServiceFactory.class, - new ManagedServiceFactory() { - @Override - public String getName() { - return ""; - } - - @Override - public void updated( - String s, Dictionary<String, ?> dictionary) - throws ConfigurationException { + ServiceTracker serviceTracker = new ServiceTracker<Service, Service>( + bundleContext, Service.class, null) { - addedLatch.countDown(); - } + @Override + public Service addingService(ServiceReference<Service> reference) { + addedLatch.countDown(); - @Override - public void deleted(String s) { + return null; + } + }; - } - }, - new Hashtable<String, Object>() {{ - put("service.pid", "test.configuration"); - }}); + serviceTracker.open(); CountDownLatch deletedLatch = new CountDownLatch(3); - ServiceRegistration<?> deletedServiceRegistration = - bundleContext.registerService( - ManagedServiceFactory.class, - new ManagedServiceFactory() { - @Override - public String getName() { - return ""; - } - - @Override - public void updated( - String s, Dictionary<String, ?> dictionary) - throws ConfigurationException { - - } - - @Override - public void deleted(String s) { - deletedLatch.countDown(); - } - }, - new Hashtable<String, Object>() {{ - put("service.pid", "test.configuration"); - }}); + ServiceTracker serviceTracker2 = new ServiceTracker<Service, Service>( + bundleContext, Service.class, null) { + + @Override + public void removedService( + ServiceReference<Service> reference, + Service service) { + + deletedLatch.countDown(); + } + }; + + serviceTracker2.open(); Configuration configuration = configurationAdmin.createFactoryConfiguration("test.configuration"); @@ -572,9 +609,9 @@ public class DSLTest { bundleContext.getServiceReferences( Service.class, "(test.configuration=*)").size()); - addedServiceRegistration.unregister(); + serviceTracker.close(); - deletedServiceRegistration.unregister(); + serviceTracker2.close(); result.close();