| /* |
| * 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 java.io.IOException; |
| import java.util.Dictionary; |
| import java.util.Hashtable; |
| |
| import org.apache.felix.scr.impl.Activator; |
| import org.apache.felix.scr.impl.BundleComponentActivator; |
| import org.apache.felix.scr.impl.ComponentRegistry; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.ServiceRegistration; |
| 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 org.osgi.service.log.LogService; |
| |
| public class ConfigurationSupport implements ConfigurationListener |
| { |
| |
| final ComponentRegistry m_registry; |
| |
| // the service m_registration of the ConfigurationListener service |
| private ServiceRegistration m_registration; |
| |
| public ConfigurationSupport(final BundleContext bundleContext, final ComponentRegistry registry) |
| { |
| this.m_registry = registry; |
| |
| // register as listener for configurations |
| Dictionary props = new Hashtable(); |
| 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); |
| } |
| |
| public void dispose() |
| { |
| if (this.m_registration != null) |
| { |
| this.m_registration.unregister(); |
| this.m_registration = null; |
| } |
| } |
| |
| // ---------- BaseConfigurationSupport overwrites |
| |
| public void configureComponentHolder(final ComponentHolder holder) |
| { |
| |
| // 112.7 configure unless configuration not required |
| if (!holder.getComponentMetadata().isConfigurationIgnored()) |
| { |
| final BundleContext bundleContext = holder.getActivator().getBundleContext(); |
| final String bundleLocation = bundleContext.getBundle().getLocation(); |
| final String name = holder.getComponentMetadata().getName(); |
| |
| final ServiceReference caRef = bundleContext.getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN); |
| if (caRef != null) |
| { |
| final ConfigurationAdmin ca = (ConfigurationAdmin) bundleContext.getService(caRef); |
| if (ca != null) |
| { |
| try |
| { |
| final Configuration[] factory = findFactoryConfigurations(ca, name); |
| if (factory != null) |
| { |
| for (int i = 0; i < factory.length; i++) |
| { |
| final String pid = factory[i].getPid(); |
| final Dictionary props = getConfiguration(ca, pid, bundleLocation); |
| holder.configurationUpdated(pid, props); |
| } |
| } |
| else |
| { |
| // check for configuration and configure the holder |
| final Configuration singleton = findSingletonConfiguration(ca, name); |
| if (singleton != null) |
| { |
| final Dictionary props = getConfiguration(ca, name, bundleLocation); |
| holder.configurationUpdated(name, props); |
| } |
| } |
| } |
| finally |
| { |
| bundleContext.ungetService(caRef); |
| } |
| } |
| } |
| } |
| } |
| |
| // ---------- ServiceListener |
| |
| public void configureComponentHolders(final ServiceReference 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 |
| |
| /** |
| * Called by the Configuration Admin service if a configuration is updated |
| * or removed. |
| * <p> |
| * This method is really only called upon configuration changes; it is not |
| * called for existing configurations upon startup of the Configuration |
| * Admin service. To bridge this gap, the |
| * {@link #serviceChanged(ServiceEvent)} method called when the |
| * Configuration Admin service is registered calls this method for all |
| * existing configurations to be able to foward existing configurations to |
| * components. |
| * |
| * @param event The configuration change event |
| */ |
| public void configurationEvent(ConfigurationEvent event) |
| { |
| final String pid = event.getPid(); |
| final String factoryPid = event.getFactoryPid(); |
| |
| final ComponentHolder cm; |
| if (factoryPid == null) |
| { |
| cm = this.m_registry.getComponentHolder(pid); |
| } |
| else |
| { |
| cm = this.m_registry.getComponentHolder(factoryPid); |
| } |
| |
| Activator.log(LogService.LOG_DEBUG, null, "configurationEvent: Handling " |
| + ((event.getType() == ConfigurationEvent.CM_DELETED) ? "DELETE" : "UPDATE") + " of Configuration PID=" |
| + pid, null); |
| |
| if (cm != null && !cm.getComponentMetadata().isConfigurationIgnored()) |
| { |
| switch (event.getType()) |
| { |
| case ConfigurationEvent.CM_DELETED: |
| cm.configurationDeleted(pid); |
| break; |
| |
| case ConfigurationEvent.CM_UPDATED: |
| final BundleComponentActivator activator = cm.getActivator(); |
| if (activator == null) |
| { |
| break; |
| } |
| |
| final BundleContext bundleContext = activator.getBundleContext(); |
| if (bundleContext == null) |
| { |
| break; |
| } |
| |
| final ServiceReference caRef = bundleContext |
| .getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN); |
| if (caRef != null) |
| { |
| try |
| { |
| final ConfigurationAdmin ca = (ConfigurationAdmin) bundleContext.getService(caRef); |
| if (ca != null) |
| { |
| try |
| { |
| final Dictionary dict = getConfiguration(ca, pid, bundleContext.getBundle() |
| .getLocation()); |
| if (dict != null) |
| { |
| cm.configurationUpdated(pid, dict); |
| } |
| } |
| finally |
| { |
| bundleContext.ungetService(caRef); |
| } |
| } |
| } |
| catch (IllegalStateException ise) |
| { |
| // If the bundle has been stopped conurrently |
| } |
| } |
| break; |
| |
| default: |
| Activator.log(LogService.LOG_WARNING, null, "Unknown ConfigurationEvent type " + event.getType(), |
| null); |
| } |
| } |
| } |
| |
| private Dictionary getConfiguration(final ConfigurationAdmin ca, final String pid, final String bundleLocation) |
| { |
| try |
| { |
| final Configuration cfg = ca.getConfiguration(pid); |
| if (bundleLocation.equals(cfg.getBundleLocation()) || Activator.hasCtWorkaround()) |
| { |
| return cfg.getProperties(); |
| } |
| |
| // configuration belongs to another bundle, cannot be used here |
| Activator.log(LogService.LOG_ERROR, null, "Cannot use configuration pid=" + pid + " for bundle " |
| + bundleLocation + " because it belongs to bundle " + cfg.getBundleLocation(), null); |
| } |
| catch (IOException ioe) |
| { |
| Activator.log(LogService.LOG_WARNING, null, "Failed reading configuration for pid=" + pid, ioe); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the configuration whose PID equals the given pid. If no such |
| * configuration exists, <code>null</code> is returned. |
| * |
| * @param ctx |
| * @param pid |
| * @return |
| */ |
| public Configuration findSingletonConfiguration(final ConfigurationAdmin ca, final String pid) |
| { |
| final String filter = "(service.pid=" + pid + ")"; |
| final Configuration[] cfg = findConfigurations(ca, filter); |
| return (cfg == null || cfg.length == 0) ? null : cfg[0]; |
| } |
| |
| /** |
| * Returns all configurations whose factory PID equals the given factory PID |
| * or <code>null</code> if no such configurations exist |
| * |
| * @param ctx |
| * @param factoryPid |
| * @return |
| */ |
| public Configuration[] findFactoryConfigurations(final ConfigurationAdmin ca, final String factoryPid) |
| { |
| final String filter = "(service.factoryPid=" + factoryPid + ")"; |
| return findConfigurations(ca, filter); |
| } |
| |
| private Configuration[] findConfigurations(final ConfigurationAdmin ca, final String filter) |
| { |
| try |
| { |
| return ca.listConfigurations(filter); |
| } |
| catch (IOException ioe) |
| { |
| Activator.log(LogService.LOG_WARNING, null, "Problem listing configurations for filter=" + filter, ioe); |
| } |
| catch (InvalidSyntaxException ise) |
| { |
| Activator.log(LogService.LOG_ERROR, null, "Invalid Configuration selection filter " + filter, ise); |
| } |
| |
| // no factories in case of problems |
| return null; |
| } |
| } |