FELIX-5079 Register configuration listener per config admin found
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1717854 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
index 3672442..79fbbad 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
@@ -151,7 +151,7 @@
// prepare component registry
m_componentBundles = new HashMap<Long, BundleComponentActivator>();
- m_componentRegistry = new ComponentRegistry( m_context );
+ m_componentRegistry = new ComponentRegistry( );
final ServiceComponentRuntime runtime = new ServiceComponentRuntimeImpl(m_context, m_componentRegistry);
m_runtime_reg = m_context.registerService(ServiceComponentRuntime.class,
@@ -206,7 +206,6 @@
// dispose component registry
if ( m_componentRegistry != null )
{
- m_componentRegistry.dispose();
m_componentRegistry = null;
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
index b6c8d77..2a6aeb3 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
@@ -31,12 +31,13 @@
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.felix.scr.impl.config.ComponentHolder;
+import org.apache.felix.scr.impl.config.ConfigAdminTracker;
+import org.apache.felix.scr.impl.config.RegionConfigurationSupport;
import org.apache.felix.scr.impl.config.ScrConfiguration;
import org.apache.felix.scr.impl.helper.Logger;
import org.apache.felix.scr.impl.manager.AbstractComponentManager;
@@ -65,6 +66,7 @@
*/
public class BundleComponentActivator implements Logger, ExtendedServiceListenerContext<ExtendedServiceEvent>
{
+
// global component registration
private final ComponentRegistry m_componentRegistry;
@@ -74,8 +76,8 @@
// The bundle context owning the registered component
private final BundleContext m_context;
- // This is a list of component instance managers that belong to a particular bundle
- private final List<ComponentHolder<?>> m_managers = new ArrayList<ComponentHolder<?>>();
+ // This is a list of component holders that belong to a particular bundle
+ private final List<ComponentHolder<?>> m_holders = new ArrayList<ComponentHolder<?>>();
// The Configuration Admin tracker providing configuration for components
private final ServiceTracker<LogService, LogService> m_logService;
@@ -89,6 +91,8 @@
// the configuration
private final ScrConfiguration m_configuration;
+
+ private final ConfigAdminTracker configAdminTracker;
private final Map<String, ListenerInfo> listenerMap = new HashMap<String, ListenerInfo>();
@@ -268,6 +272,16 @@
}
initialize(descriptorLocations);
+ ConfigAdminTracker tracker = null;
+ for (ComponentHolder<?> holder: m_holders)
+ {
+ if (!holder.getComponentMetadata().isConfigurationIgnored())
+ {
+ tracker = new ConfigAdminTracker(this, componentRegistry);
+ break;
+ }
+ }
+ configAdminTracker = tracker;
}
/**
@@ -318,7 +332,7 @@
void initialEnable()
{
//enable all the enabled components
- for (ComponentHolder<?> componentHolder : m_managers)
+ for (ComponentHolder<?> componentHolder : m_holders)
{
log(LogService.LOG_DEBUG,
"BundleComponentActivator : Bundle [{0}] May enable component holder {1}",
@@ -459,7 +473,7 @@
// register the component after validation
m_componentRegistry.registerComponentHolder(key, holder);
- m_managers.add(holder);
+ m_holders.add(holder);
log(LogService.LOG_DEBUG,
"BundleComponentActivator : Bundle [{0}] ComponentHolder created for {1}",
@@ -509,7 +523,7 @@
}
}
}
-
+
/**
* Dispose of this component activator instance and all the component
* managers.
@@ -520,10 +534,10 @@
{
log(LogService.LOG_DEBUG,
"BundleComponentActivator : Bundle [{0}] will destroy {1} instances",
- new Object[] { m_bundle.getBundleId(), m_managers.size() }, null, null,
+ new Object[] { m_bundle.getBundleId(), m_holders.size() }, null, null,
null);
- for (ComponentHolder<?> holder : m_managers)
+ for (ComponentHolder<?> holder : m_holders)
{
try
{
@@ -542,6 +556,7 @@
}
}
+ configAdminTracker.dispose();
log(LogService.LOG_DEBUG, "BundleComponentActivator : Bundle [{0}] STOPPED",
new Object[] { m_bundle.getBundleId() }, null, null, null);
@@ -666,7 +681,7 @@
// if all components are selected
if (name == null)
{
- return m_managers;
+ return m_holders;
}
ComponentHolder<?> componentHolder = m_componentRegistry.getComponentHolder(
@@ -829,4 +844,15 @@
m_componentRegistry.registerMissingDependency(dependencyManager,
serviceReference, trackingCount);
}
+
+ public void setRegionConfigurationSupport(RegionConfigurationSupport rcs) {
+ for (ComponentHolder<?> holder: m_holders)
+ {
+ rcs.configureComponentHolder(holder);
+ }
+ }
+
+ public void unsetRegionConfigurationSupport(RegionConfigurationSupport rcs) {
+ // TODO anything needed?
+ }
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
index c09506a..5f7b95c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
@@ -26,21 +26,18 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.felix.scr.impl.config.ComponentHolder;
import org.apache.felix.scr.impl.config.ConfigurableComponentHolder;
-import org.apache.felix.scr.impl.config.ConfigurationSupport;
+import org.apache.felix.scr.impl.config.RegionConfigurationSupport;
import org.apache.felix.scr.impl.manager.AbstractComponentManager;
import org.apache.felix.scr.impl.manager.DependencyManager;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
-import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentException;
import org.osgi.service.log.LogService;
@@ -50,15 +47,12 @@
* The <code>ComponentRegistry</code> class acts as the global registry for
* components by name and by component ID.
*/
-public class ComponentRegistry implements ServiceListener
+public class ComponentRegistry
{
// the name of the ConfigurationAdmin service
public static final String CONFIGURATION_ADMIN = "org.osgi.service.cm.ConfigurationAdmin";
- // the bundle context
- private BundleContext m_bundleContext;
-
/**
* The map of known components indexed by component name. The values are
* either null (for name reservations) or implementations
@@ -91,7 +85,7 @@
*
* @see #registerComponentHolder(String, ComponentHolder)
* @see #unregisterComponentHolder(String)
- * @see ConfigurationSupport#configurationEvent(org.osgi.service.cm.ConfigurationEvent)
+ * @see RegionConfigurationSupport#configurationEvent(org.osgi.service.cm.ConfigurationEvent)
*/
private final Map<String, Set<ComponentHolder<?>>> m_componentHoldersByPid;
@@ -112,50 +106,16 @@
*/
private long m_componentCounter = -1;
- // ConfigurationAdmin support -- created on demand upon availability of
- // the ConfigurationAdmin service
- private ConfigurationSupport configurationSupport;
-
private final Map<ServiceReference<?>, List<Entry<?, ?>>> m_missingDependencies = new HashMap<ServiceReference<?>, List<Entry<?, ?>>>( );
- protected ComponentRegistry( final BundleContext context )
+ protected ComponentRegistry( )
{
- m_bundleContext = context;
m_componentHoldersByName = new HashMap<ComponentRegistryKey, ComponentHolder<?>>();
m_componentHoldersByPid = new HashMap<String, Set<ComponentHolder<?>>>();
m_componentsById = new HashMap<Long, AbstractComponentManager<?>>();
- // keep me informed on ConfigurationAdmin state changes
- try
- {
- context.addServiceListener(this, "(objectclass=" + CONFIGURATION_ADMIN + ")");
- }
- catch (InvalidSyntaxException ise)
- {
- // not expected (filter is tested valid)
- }
-
- // If the Configuration Admin Service is already registered, setup
- // configuration support immediately
- if (context.getServiceReference(CONFIGURATION_ADMIN) != null)
- {
- getOrCreateConfigurationSupport();
- }
}
- public void dispose()
- {
- m_bundleContext.removeServiceListener(this);
-
- if (configurationSupport != null)
- {
- configurationSupport.dispose();
- configurationSupport = null;
- }
- }
-
-
-
//---------- ComponentManager registration by component Id
/**
@@ -310,11 +270,6 @@
}
}
- if (configurationSupport != null)
- {
- configurationSupport.configureComponentHolder(componentHolder);
- }
-
}
/**
@@ -459,40 +414,6 @@
//---------- ServiceListener
- /**
- * Called if the Configuration Admin service changes state. This
- * implementation is mainly interested in the Configuration Admin service
- * being registered <i>after</i> the Declarative Services setup to be able
- * to forward existing configuration.
- *
- * @param event The service change event
- */
- public void serviceChanged(ServiceEvent event)
- {
- if (event.getType() == ServiceEvent.REGISTERED)
- {
- ConfigurationSupport configurationSupport = getOrCreateConfigurationSupport();
-
- final ServiceReference<ConfigurationAdmin> caRef = (ServiceReference<ConfigurationAdmin>) event.getServiceReference();
- final ConfigurationAdmin service = m_bundleContext.getService(caRef);
- if (service != null)
- {
- try
- {
- configurationSupport.configureComponentHolders(caRef, service);
- }
- finally
- {
- m_bundleContext.ungetService(caRef);
- }
- }
- }
- else if (event.getType() == ServiceEvent.UNREGISTERING)
- {
- disposeConfigurationSupport();
- }
- }
-
//---------- Helper method
/**
@@ -537,24 +458,6 @@
return false;
}
- private ConfigurationSupport getOrCreateConfigurationSupport()
- {
- if (configurationSupport == null)
- {
- configurationSupport = new ConfigurationSupport(m_bundleContext, this);
- }
- return configurationSupport;
- }
-
- private void disposeConfigurationSupport()
- {
- if (configurationSupport != null)
- {
- this.configurationSupport.dispose();
- this.configurationSupport = null;
- }
- }
-
public synchronized <T> void missingServicePresent( final ServiceReference<T> serviceReference, ComponentActorThread actor )
{
final List<Entry<?, ?>> dependencyManagers = m_missingDependencies.remove( serviceReference );
@@ -618,4 +521,46 @@
return trackingCount;
}
}
+
+ private final ConcurrentMap<Long, RegionConfigurationSupport> bundleToRcsMap = new ConcurrentHashMap<Long, RegionConfigurationSupport>();
+
+ public RegionConfigurationSupport registerRegionConfigurationSupport(
+ RegionConfigurationSupport trialRcs) {
+ Long bundleId = trialRcs.getBundleId();
+ RegionConfigurationSupport existing = null;
+ RegionConfigurationSupport previous = null;
+ while (true)
+ {
+ existing = bundleToRcsMap.putIfAbsent(bundleId, trialRcs);
+ if (existing == null)
+ {
+ trialRcs.start();
+ return trialRcs;
+ }
+ if (existing == previous)
+ {
+ //the rcs we referenced is still current
+ return existing;
+ }
+ if (existing.reference())
+ {
+ //existing can still be used
+ previous = existing;
+ }
+ else
+ {
+ //existing was discarded in another thread, start over
+ previous = null;
+ }
+ }
+ }
+
+ public void unregisterRegionConfigurationSupport(
+ RegionConfigurationSupport rcs) {
+ if (rcs.dereference())
+ {
+ bundleToRcsMap.remove(rcs.getBundleId());
+ }
+
+ }
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
index 122fb75..59e0ca5 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
@@ -33,7 +33,7 @@
* component instances configured through either singleton configurations (or
* no configuration at all) and factory configurations.
* <p>
- * Instances of this interface are managed by the {@link ConfigurationSupport}
+ * Instances of this interface are managed by the {@link RegionConfigurationSupport}
* class on behalf of the
* {@link org.apache.felix.scr.impl.BundleComponentActivator} and the
* {@link org.apache.felix.scr.impl.ComponentRegistry}.
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigAdminTracker.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigAdminTracker.java
new file mode 100644
index 0000000..dfc65dd
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigAdminTracker.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.config;
+
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.ComponentRegistry;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class ConfigAdminTracker
+{
+ public static final String CONFIGURATION_ADMIN = "org.osgi.service.cm.ConfigurationAdmin";
+
+ private final ServiceTracker<ConfigurationAdmin, RegionConfigurationSupport> configAdminTracker;
+
+ static ConfigAdminTracker getRegionConfigurationSupport(final BundleComponentActivator bundleComponentActivator, final ComponentRegistry registry, final Bundle dsBundle)
+ {
+ Class<?> ourCA;
+ Class<?> theirCA;
+ try
+ {
+ ourCA = dsBundle.loadClass(CONFIGURATION_ADMIN);
+ }
+ catch (ClassNotFoundException e)
+ {
+ return null;
+ }
+ try
+ {
+ Bundle bundle = bundleComponentActivator.getBundleContext().getBundle();
+ if ( bundle == null )
+ {
+ return null;
+ }
+ theirCA = dsBundle.loadClass(CONFIGURATION_ADMIN);
+ }
+ catch (ClassNotFoundException e)
+ {
+ return null;
+ }
+ if ( ourCA != theirCA )
+ {
+ return null;
+ }
+ ConfigAdminTracker tracker = new ConfigAdminTracker(bundleComponentActivator, registry);
+ return tracker;
+ }
+
+ public ConfigAdminTracker(final BundleComponentActivator bundleComponentActivator, final ComponentRegistry registry)
+ {
+
+ //TODO this assumes that there is 0 or 1 ca service visible to the bundle being extended.
+ //Is this sure to be true?
+ configAdminTracker = new ServiceTracker<ConfigurationAdmin, RegionConfigurationSupport>(bundleComponentActivator.getBundleContext(),
+ CONFIGURATION_ADMIN,
+ new ServiceTrackerCustomizer<ConfigurationAdmin, RegionConfigurationSupport>()
+ {
+
+ public RegionConfigurationSupport addingService(
+ ServiceReference<ConfigurationAdmin> reference) {
+ RegionConfigurationSupport trialRcs = new RegionConfigurationSupport(reference, registry);
+ RegionConfigurationSupport rcs = registry.registerRegionConfigurationSupport(trialRcs);
+ bundleComponentActivator.setRegionConfigurationSupport(rcs);
+ return rcs;
+ }
+
+ public void modifiedService(
+ ServiceReference<ConfigurationAdmin> reference,
+ RegionConfigurationSupport service) {
+ }
+
+ public void removedService(
+ ServiceReference<ConfigurationAdmin> reference,
+ RegionConfigurationSupport rcs) {
+ registry.unregisterRegionConfigurationSupport(rcs);
+ bundleComponentActivator.unsetRegionConfigurationSupport(rcs);
+ }
+ });
+
+ configAdminTracker.open();
+ }
+
+ public void dispose()
+ {
+ configAdminTracker.close();
+ }
+
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
index 12031ce..55d549c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
@@ -644,8 +644,7 @@
return m_enablePromise;
}
wait( m_disablePromise );
-
-
+
List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>();
synchronized ( m_components )
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java b/scr/src/main/java/org/apache/felix/scr/impl/config/RegionConfigurationSupport.java
similarity index 95%
rename from scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
rename to scr/src/main/java/org/apache/felix/scr/impl/config/RegionConfigurationSupport.java
index 930973e..1c438a9 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/RegionConfigurationSupport.java
@@ -26,6 +26,7 @@
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.felix.scr.impl.Activator;
import org.apache.felix.scr.impl.BundleComponentActivator;
@@ -43,9 +44,11 @@
import org.osgi.service.cm.ConfigurationListener;
import org.osgi.service.cm.ConfigurationPermission;
import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
-public class ConfigurationSupport implements ConfigurationListener
+public class RegionConfigurationSupport implements ConfigurationListener
{
+
private static final ChangeCount changeCounter;
static
{
@@ -68,33 +71,67 @@
changeCounter = cc;
}
+ private final BundleContext caBundleContext;
+ private final Long bundleId;
+
// the registry of components to be configured
private final ComponentRegistry m_registry;
+
+ private final AtomicInteger reference = new AtomicInteger(1);
// the service m_registration of the ConfigurationListener service
- private ServiceRegistration<?> m_registration;
+ private ServiceRegistration<ConfigurationListener> m_registration;
+
- public ConfigurationSupport(final BundleContext bundleContext, final ComponentRegistry registry)
+ /**
+ *
+ * @param bundleContext of the ConfigurationAdmin we are tracking
+ * @param registry
+ */
+ public RegionConfigurationSupport(ServiceReference<ConfigurationAdmin> reference, final ComponentRegistry registry)
{
this.m_registry = registry;
-
+ Bundle bundle = reference.getBundle();
+ this.bundleId = bundle.getBundleId();
+ this.caBundleContext = bundle.getBundleContext();
+ }
+
+ public void start()
+ {
// register as listener for configurations
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put(Constants.SERVICE_DESCRIPTION, "Declarative Services Configuration Support Listener");
props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
- this.m_registration = bundleContext.registerService(new String[]
- { "org.osgi.service.cm.ConfigurationListener" }, this, props);
+ this.m_registration = caBundleContext.registerService(ConfigurationListener.class, this, props);
+
}
- public void dispose()
- {
- if (this.m_registration != null)
- {
+ public Long getBundleId()
+ {
+ return bundleId;
+ }
+
+ public boolean reference()
+ {
+ if (reference.get() == 0)
+ {
+ return false;
+ }
+ reference.incrementAndGet();
+ return true;
+ }
+
+ public boolean dereference()
+ {
+ if ( reference.decrementAndGet() ==0 )
+ {
this.m_registration.unregister();
- this.m_registration = null;
- }
- }
-
+ this.m_registration = null;
+ return true;
+ }
+ return false;
+ }
+
/**
* The return value is only relevant for the call from {@link #configurationEvent(ConfigurationEvent)}
* in the case of a deleted configuration which is not a factory configuration!
@@ -210,26 +247,6 @@
return false;
}
- // ---------- ServiceListener
-
- public void configureComponentHolders(final ServiceReference<ConfigurationAdmin> configurationAdminReference,
- final Object configurationAdmin)
- {
- if (configurationAdmin instanceof ConfigurationAdmin)
- {
- Configuration[] configs = findConfigurations((ConfigurationAdmin) configurationAdmin, null);
- if (configs != null)
- {
- for (int i = 0; i < configs.length; i++)
- {
- ConfigurationEvent cfgEvent = new ConfigurationEvent(configurationAdminReference,
- ConfigurationEvent.CM_UPDATED, configs[i].getFactoryPid(), configs[i].getPid());
- configurationEvent(cfgEvent);
- }
- }
- }
- }
-
// ---------- ConfigurationListener
/**
@@ -691,4 +708,5 @@
}
}
+
}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/config/ConfigurationSupportTest.java b/scr/src/test/java/org/apache/felix/scr/impl/config/ConfigurationSupportTest.java
index f14525c..47d9791 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/config/ConfigurationSupportTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/config/ConfigurationSupportTest.java
@@ -25,7 +25,7 @@
public void testEscape()
{
- assertEquals("foo \\(&\\)", ConfigurationSupport.escape("foo (&)"));
+ assertEquals("foo \\(&\\)", RegionConfigurationSupport.escape("foo (&)"));
}
}