reworked FactoryConfigurationAdapter API
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@947624 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
index 53156a0..57e3e5d 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
@@ -173,74 +173,14 @@
return m_manager.createBundleAdapterService(bundleStateMask, bundleFilter, propagate);
}
- /**
- * Creates a new Managed Service Factory Configuration Adapter. For each new Config Admin factory configuration matching
- * the factoryPid, an adapter will be created based on the adapter implementation class.
- * The adapter will be registered with the specified interface, and with the specified adapter service properties.
- * Depending on the <code>propagate</code> parameter, every public factory configuration properties
- * (which don't start with ".") will be propagated along with the adapter service properties.
- * It will also inherit all dependencies.
- *
- * @param factoryPid the pid matching the factory configuration
- * @param update the adapter method name that will be notified when the factory configuration is created/updated.
- * @param adapterInterface the interface to use when registering adapters (can be either a String, String array)
- * @param adapterImplementation the implementation of the adapter (can be a Class or an Object instance)
- * @param adapterProperties additional properties to use with the service registration
- * @param propagate true if public factory configuration should be propagated to the adapter service properties
- * @return a service that acts as a factory for generating the managed service factory configuration adapter
- */
- public Service createFactoryConfigurationAdapterService(String factoryPid, String update, Object adapterImplementation, String adapterInterface, Dictionary adapterProperties, boolean propagate) {
- return m_manager.createFactoryConfigurationAdapterService(factoryPid, update, adapterImplementation, adapterInterface, adapterProperties, propagate);
+ public Service createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate) {
+ return m_manager.createFactoryConfigurationAdapterService(factoryPid, update, propagate);
}
- /**
- * Creates a new Managed Service Factory Configuration Adapter. For each new Config Admin factory configuration matching
- * the factoryPid, an adapter will be created based on the adapter implementation class.
- * The adapter will be registered with the specified interface, and with the specified adapter service properties.
- * Depending on the <code>propagate</code> parameter, every public factory configuration properties
- * (which don't start with ".") will be propagated along with the adapter service properties.
- * It will also inherit all dependencies.
- *
- * @param factoryPid the pid matching the factory configuration
- * @param update the adapter method name that will be notified when the factory configuration is created/updated.
- * @param adapterInterfaces the interfaces to use when registering adapters (can be either a String, String array)
- * @param adapterImplementation the implementation of the adapter (can be a Class or an Object instance)
- * @param adapterProperties additional properties to use with the service registration
- * @param propagate true if public factory configuration should be propagated to the adapter service properties
- * @return a service that acts as a factory for generating the managed service factory configuration adapter
- */
- public Service createFactoryConfigurationAdapterService(String factoryPid, String update, Object adapterImplementation, String[] adapterInterfaces, Dictionary adapterProperties, boolean propagate) {
- return m_manager.createFactoryConfigurationAdapterService(factoryPid, update, adapterImplementation, adapterInterfaces, adapterProperties, propagate);
- }
-
- /**
- * Creates a new Managed Service Factory Configuration Adapter with meta type support. For each new Config Admin factory configuration matching
- * the factoryPid, an adapter will be created based on the adapter implementation class.
- * The adapter will be registered with the specified interface, and with the specified adapter service properties.
- * Depending on the <code>propagate</code> parameter, every public factory configuration properties
- * (which don't start with ".") will be propagated along with the adapter service properties.
- * It will also inherit all dependencies.
- *
- * @param factoryPid the pid matching the factory configuration
- * @param update the adapter method name that will be notified when the factory configuration is created/updated.
- * @param adapterInterfaces the interfaces to use when registering adapters (can be either a String, String array)
- * @param adapterImplementation the implementation of the adapter (can be a Class or an Object instance)
- * @param adapterProperties additional properties to use with the service registration
- * @param propagate true if public factory configuration should be propagated to the adapter service properties
- * @param heading The label used to display the tab name (or section) where the properties are displayed. Example: "Printer Service"
- * @param desc A human readable description of the factory PID this configuration is associated with. Example: "Configuration for the PrinterService bundle"
- * @param localization Points to the basename of the Properties file that can localize the Meta Type informations.
- * The default localization base name for the properties is OSGI-INF/l10n/bundle, but can
- * be overridden by the manifest Bundle-Localization header (see core specification, in section Localization on page 68).
- * You can specify a specific localization basename file using this parameter (e.g. <code>"person"</code>
- * will match person_du_NL.properties in the root bundle directory).
- * @param propertiesMetaData Array of MetaData regarding configuration properties
- * @return a service that acts as a factory for generating the managed service factory configuration adapter
- */
- public Service createFactoryConfigurationAdapterService(String factoryPid, String update, Object adapterImplementation, String[] adapterInterfaces, Dictionary adapterProperties, boolean propagate,
+ public Service createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate,
String heading, String desc, String localization, PropertyMetaData[] propertiesMetaData)
{
- return m_manager.createFactoryConfigurationAdapterService(factoryPid, update, adapterImplementation, adapterInterfaces, adapterProperties, propagate,
+ return m_manager.createFactoryConfigurationAdapterService(factoryPid, update, propagate,
heading, desc, localization, propertiesMetaData);
}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
index 2e60ec5..15f8719 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
@@ -20,8 +20,6 @@
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Hashtable;
import java.util.List;
import org.apache.felix.dm.dependencies.BundleDependency;
@@ -33,8 +31,7 @@
import org.apache.felix.dm.impl.AdapterServiceImpl;
import org.apache.felix.dm.impl.AspectServiceImpl;
import org.apache.felix.dm.impl.BundleAdapterServiceImpl;
-import org.apache.felix.dm.impl.FactoryConfigurationAdapterImpl;
-import org.apache.felix.dm.impl.FactoryConfigurationAdapterMetaTypeImpl;
+import org.apache.felix.dm.impl.FactoryConfigurationAdapterServiceImpl;
import org.apache.felix.dm.impl.Logger;
import org.apache.felix.dm.impl.ResourceAdapterServiceImpl;
import org.apache.felix.dm.impl.ServiceImpl;
@@ -47,8 +44,6 @@
import org.apache.felix.dm.resources.Resource;
import org.apache.felix.dm.service.Service;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.service.cm.ManagedServiceFactory;
/**
* The dependency manager manages all services and their dependencies. Using
@@ -303,81 +298,55 @@
* (which don't start with ".") will be propagated along with the adapter service properties.
* It will also inherit all dependencies.
*
+ * <h3>Usage Example</h3>
+ *
+ * <blockquote>
+ * manager.createFactoryConfigurationAdapterService("MyFactoryPid", "update", true)
+ * // The interface to use when registering adapter
+ * .setInterface(AdapterService.class, new Hashtable() {{ put("foo", "bar"); }})
+ * // the implementation of the adapter
+ * .setImplementation(AdapterServiceImpl.class);
+ * <pre>
+ * </pre>
+ * </blockquote>
* @param factoryPid the pid matching the factory configuration
* @param update the adapter method name that will be notified when the factory configuration is created/updated.
- * @param adapterInterface the interface to use when registering adapters (can be either a String, String array)
- * @param adapterImplementation the implementation of the adapter (can be a Class or an Object instance)
- * @param adapterProperties additional properties to use with the service registration
* @param propagate true if public factory configuration should be propagated to the adapter service properties
* @return a service that acts as a factory for generating the managed service factory configuration adapter
*/
- public Service createFactoryConfigurationAdapterService(String factoryPid, String update, Object adapterImplementation, String adapterInterface, Dictionary adapterProperties, boolean propagate) {
- Hashtable props = new Hashtable();
- props.put(Constants.SERVICE_PID, factoryPid);
- return createService()
- .setInterface(ManagedServiceFactory.class.getName(), props)
- .setImplementation(new FactoryConfigurationAdapterImpl(factoryPid, update, adapterImplementation, adapterInterface, adapterProperties, propagate));
+ public Service createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate) {
+ return new FactoryConfigurationAdapterServiceImpl(this, factoryPid, update, propagate);
}
/**
- * Creates a new Managed Service Factory Configuration Adapter. For each new Config Admin factory configuration matching
- * the factoryPid, an adapter will be created based on the adapter implementation class.
- * The adapter will be registered with the specified interface, and with the specified adapter service properties.
- * Depending on the <code>propagate</code> parameter, every public factory configuration properties
+ * Creates a new Managed Service Factory Configuration Adapter with meta type support. For each new Config Admin
+ * factory configuration matching the factoryPid, an adapter will be created based on the adapter implementation
+ * class. The adapter will be registered with the specified interface, and with the specified adapter service
+ * properties. Depending on the <code>propagate</code> parameter, every public factory configuration properties
* (which don't start with ".") will be propagated along with the adapter service properties.
* It will also inherit all dependencies.
*
* @param factoryPid the pid matching the factory configuration
* @param update the adapter method name that will be notified when the factory configuration is created/updated.
- * @param adapterInterfaces the interfaces to use when registering adapters (can be either a String, String array)
- * @param adapterImplementation the implementation of the adapter (can be a Class or an Object instance)
- * @param adapterProperties additional properties to use with the service registration
* @param propagate true if public factory configuration should be propagated to the adapter service properties
- * @return a service that acts as a factory for generating the managed service factory configuration adapter
- */
- public Service createFactoryConfigurationAdapterService(String factoryPid, String update, Object adapterImplementation, String[] adapterInterfaces, Dictionary adapterProperties, boolean propagate) {
- Hashtable props = new Hashtable();
- props.put(Constants.SERVICE_PID, factoryPid);
- return createService()
- .setInterface(ManagedServiceFactory.class.getName(), props)
- .setImplementation(new FactoryConfigurationAdapterImpl(factoryPid, update, adapterImplementation, adapterInterfaces, adapterProperties, propagate));
- }
-
- /**
- * Creates a new Managed Service Factory Configuration Adapter with meta type support. For each new Config Admin factory configuration matching
- * the factoryPid, an adapter will be created based on the adapter implementation class.
- * The adapter will be registered with the specified interface, and with the specified adapter service properties.
- * Depending on the <code>propagate</code> parameter, every public factory configuration properties
- * (which don't start with ".") will be propagated along with the adapter service properties.
- * It will also inherit all dependencies.
- *
- * @param factoryPid the pid matching the factory configuration
- * @param update the adapter method name that will be notified when the factory configuration is created/updated.
- * @param adapterInterfaces the interfaces to use when registering adapters (can be either a String, String array)
- * @param adapterImplementation the implementation of the adapter (can be a Class or an Object instance)
- * @param adapterProperties additional properties to use with the service registration
- * @param propagate true if public factory configuration should be propagated to the adapter service properties
- * @param heading The label used to display the tab name (or section) where the properties are displayed. Example: "Printer Service"
- * @param desc A human readable description of the factory PID this configuration is associated with. Example: "Configuration for the PrinterService bundle"
+ * @param heading The label used to display the tab name (or section) where the properties are displayed.
+ * Example: "Printer Service"
+ * @param desc A human readable description of the factory PID this configuration is associated with.
+ * Example: "Configuration for the PrinterService bundle"
* @param localization Points to the basename of the Properties file that can localize the Meta Type informations.
* The default localization base name for the properties is OSGI-INF/l10n/bundle, but can
- * be overridden by the manifest Bundle-Localization header (see core specification, in section Localization on page 68).
- * You can specify a specific localization basename file using this parameter (e.g. <code>"person"</code>
- * will match person_du_NL.properties in the root bundle directory).
+ * be overridden by the manifest Bundle-Localization header (see core specification, in section Localization
+ * on page 68). You can specify a specific localization basename file using this parameter
+ * (e.g. <code>"person"</code> will match person_du_NL.properties in the root bundle directory).
* @param propertiesMetaData Array of MetaData regarding configuration properties
* @return a service that acts as a factory for generating the managed service factory configuration adapter
*/
- public Service createFactoryConfigurationAdapterService(String factoryPid, String update, Object adapterImplementation, String[] adapterInterfaces, Dictionary adapterProperties, boolean propagate,
- String heading, String desc, String localization, PropertyMetaData[] propertiesMetaData)
+ public Service createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate,
+ String heading, String desc, String localization,
+ PropertyMetaData[] propertiesMetaData)
{
- Hashtable props = new Hashtable();
- props.put(Constants.SERVICE_PID, factoryPid);
- FactoryConfigurationAdapterMetaTypeImpl impl =
- new FactoryConfigurationAdapterMetaTypeImpl(factoryPid, update, adapterImplementation, adapterInterfaces, adapterProperties, propagate,
- m_context, m_logger, heading, desc, localization, propertiesMetaData);
- return createService()
- .setInterface(ManagedServiceFactory.class.getName(), props)
- .setImplementation(impl);
+ return new FactoryConfigurationAdapterServiceImpl(this, factoryPid, update, propagate, m_context, m_logger,
+ heading, desc, localization, propertiesMetaData);
}
/**
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
deleted file mode 100644
index a70e70f..0000000
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterImpl.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.felix.dm.impl;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-
-import org.apache.felix.dm.DependencyManager;
-import org.apache.felix.dm.service.Service;
-import org.osgi.service.cm.ManagedServiceFactory;
-
-/**
- * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
- */
-public class FactoryConfigurationAdapterImpl extends AbstractDecorator implements ManagedServiceFactory
-{
- // The Adapter Service (we need to inherit all its dependencies).
- protected volatile Service m_service;
-
- // Our injected dependency manager
- protected volatile DependencyManager m_dm;
-
- // Our adapter implementation (either a Class, or an Object instance)
- protected final Object m_adapterImplementation;
-
- // Our adapter interface(s) (either null, a String, or a String array)
- protected final Object m_adapterInterface;
-
- // Our adapter service properties (may be null)
- protected final Dictionary m_adapterProperties;
-
- // Our Managed Service Factory PID
- protected String m_factoryPid;
-
- // The adapter "update" method used to provide the configuration
- protected String m_update;
-
- // Tells if the CM config must be propagated along with the adapter service properties
- protected boolean m_propagate;
-
- /**
- * Creates a new CM factory configuration adapter.
- *
- * @param factoryPid
- * @param updateMethod
- * @param adapterInterface
- * @param adapterImplementation
- * @param adapterProperties
- * @param propagate
- */
- public FactoryConfigurationAdapterImpl(String factoryPid, String updateMethod, Object adapterImplementation, Object adapterInterface, Dictionary adapterProperties, boolean propagate)
- {
- m_factoryPid = factoryPid;
- m_update = updateMethod;
- m_adapterImplementation = adapterImplementation;
- m_adapterInterface = adapterInterface;
- m_adapterProperties = adapterProperties;
- m_propagate = propagate;
- }
-
- /**
- * Returns the managed service factory name.
- */
- public String getName()
- {
- return m_factoryPid;
- }
-
- /**
- * Method called from our superclass, when we need to create a service.
- */
- public Service createService(Object[] properties) {
- Dictionary settings = (Dictionary) properties[0];
- Service newService = m_dm.createService();
- Object impl;
-
- try {
- impl = (m_adapterImplementation instanceof Class) ?
- ((Class) m_adapterImplementation).newInstance() : m_adapterImplementation;
- InvocationUtil.invokeCallbackMethod(impl, m_update,
- new Class[][] {{ Dictionary.class }, {}},
- new Object[][] {{ settings }, {}});
- }
-
- catch (InvocationTargetException e)
- {
- // Our super class will check if the target exception is itself a ConfigurationException.
- // In this case, it will simply re-thrown.
- throw new RuntimeException(e.getTargetException());
- }
-
- catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else {
- throw new RuntimeException(t);
- }
- }
-
- // Merge adapter service properties, with CM settings
- Dictionary serviceProperties = m_propagate ? mergeSettings(m_adapterProperties, settings) : m_adapterProperties;
-
- if (m_adapterInterface instanceof String)
- {
- newService.setInterface((String) m_adapterInterface, serviceProperties);
- }
- else if (m_adapterInterface instanceof String[])
- {
- newService.setInterface((String[]) m_adapterInterface, serviceProperties);
- }
-
- newService.setImplementation(impl);
- List dependencies = m_service.getDependencies();
- newService.add(dependencies);
- return newService;
- }
-
- /**
- * Method called from our superclass, when we need to update a Service, because
- * the configuration has changed.
- */
- public void updateService(Object[] properties)
- {
- Dictionary settings = (Dictionary) properties[0];
- Service service = (Service) properties[1];
- Object impl = service.getService();
-
- try
- {
- InvocationUtil.invokeCallbackMethod(impl, m_update,
- new Class[][] {{ Dictionary.class }, {}},
- new Object[][] {{ settings }, {}});
- if (m_adapterInterface != null && m_propagate == true) {
- settings = mergeSettings(m_adapterProperties, settings);
- service.setServiceProperties(settings);
- }
- }
-
- catch (InvocationTargetException e)
- {
- // Our super class will check if the target exception is itself a ConfigurationException.
- // In this case, it will simply re-thrown.
- throw new RuntimeException(e.getTargetException());
- }
-
- catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else {
- throw new RuntimeException(t);
- }
- }
- }
-
- /**
- * Merge CM factory configuration setting with the adapter service properties. The private CM factory configuration
- * settings are ignored. A CM factory configuration property is private if its name starts with a dot (".").
- *
- * @param adapterProperties
- * @param settings
- * @return
- */
- private Dictionary mergeSettings(Dictionary adapterProperties, Dictionary settings)
- {
- Dictionary props = new Hashtable();
-
- if (adapterProperties != null) {
- Enumeration keys = adapterProperties.keys();
- while (keys.hasMoreElements()) {
- Object key = keys.nextElement();
- Object val = adapterProperties.get(key);
- props.put(key, val);
- }
- }
-
- Enumeration keys = settings.keys();
- while (keys.hasMoreElements()) {
- Object key = keys.nextElement();
- if (! key.toString().startsWith(".")) {
- // public properties are propagated
- Object val = settings.get(key);
- props.put(key, val);
- }
- }
- return props;
- }
-}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterMetaTypeImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterMetaTypeImpl.java
deleted file mode 100644
index 4f4dd57..0000000
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterMetaTypeImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.apache.felix.dm.impl;
-
-import java.util.Dictionary;
-
-import org.apache.felix.dm.dependencies.PropertyMetaData;
-import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.metatype.MetaTypeProvider;
-import org.osgi.service.metatype.ObjectClassDefinition;
-
-public class FactoryConfigurationAdapterMetaTypeImpl extends FactoryConfigurationAdapterImpl implements MetaTypeProvider
-{
- // Our MetaType Provider for describing our properties metadata
- private MetaTypeProviderImpl m_metaType;
-
- /**
- * Creates a new CM factory configuration adapter.
- *
- * @param factoryPid
- * @param updateMethod
- * @param adapterInterface
- * @param adapterImplementation
- * @param adapterProperties
- * @param propagate
- */
- public FactoryConfigurationAdapterMetaTypeImpl(String factoryPid, String updateMethod, Object adapterImplementation, Object adapterInterface, Dictionary adapterProperties, boolean propagate,
- BundleContext bctx, Logger logger, String heading, String description, String localization, PropertyMetaData[] properyMetaData)
- {
- super(factoryPid, updateMethod, adapterImplementation, adapterInterface, adapterProperties, propagate);
- m_metaType = new MetaTypeProviderImpl(m_factoryPid, bctx, logger, null, this);
- m_metaType.setName(heading);
- m_metaType.setDescription(description);
- if (localization != null)
- {
- m_metaType.setLocalization(localization);
- }
- for (int i = 0; i < properyMetaData.length; i ++)
- {
- m_metaType.add(properyMetaData[i]);
- }
- }
-
- public String[] getLocales()
- {
- return m_metaType.getLocales();
- }
-
- public ObjectClassDefinition getObjectClassDefinition(String id, String locale)
- {
- return m_metaType.getObjectClassDefinition(id, locale);
- }
-}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java
new file mode 100644
index 0000000..cbc6ac3
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java
@@ -0,0 +1,296 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.impl;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.service.Service;
+import org.apache.felix.dm.service.ServiceStateListener;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.apache.felix.dm.dependencies.PropertyMetaData;
+import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * Factory configuration adapter service implementation. This class extends the FilterService in order to catch
+ * some Service methods for configuring actual adapter service implementation.
+ */
+public class FactoryConfigurationAdapterServiceImpl extends FilterService
+{
+ public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate)
+ {
+ super(dm.createService()); // This service will be filtered by our super class, allowing us to take control.
+ Hashtable props = new Hashtable();
+ props.put(Constants.SERVICE_PID, factoryPid);
+ m_service
+ .setInterface(ManagedServiceFactory.class.getName(), props)
+ .setImplementation(new AdapterImpl(factoryPid, update, propagate));
+ }
+
+ public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate,
+ BundleContext bctx, Logger logger, String heading, String description, String localization, PropertyMetaData[] properyMetaData)
+ {
+ super(dm.createService()); // This service will be filtered by our super class, allowing us to take control.
+ Hashtable props = new Hashtable();
+ props.put(Constants.SERVICE_PID, factoryPid);
+ String[] interfaces = new String[] {
+ ManagedServiceFactory.class.getName(),
+ MetaTypeProvider.class.getName()
+ };
+ m_service
+ .setInterface(interfaces, props)
+ .setImplementation(new MetaTypeAdapterImpl(factoryPid, update, propagate,
+ bctx, logger, heading, description,
+ localization, properyMetaData));
+ }
+
+ /**
+ * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
+ */
+ public class AdapterImpl extends AbstractDecorator implements ManagedServiceFactory
+ {
+ // Our injected dependency manager
+ protected volatile DependencyManager m_dm;
+
+ // Our Managed Service Factory PID
+ protected String m_factoryPid;
+
+ // The adapter "update" method used to provide the configuration
+ protected String m_update;
+
+ // Tells if the CM config must be propagated along with the adapter service properties
+ protected boolean m_propagate;
+
+ /**
+ * Creates a new CM factory configuration adapter.
+ *
+ * @param factoryPid
+ * @param updateMethod
+ * @param adapterInterface
+ * @param adapterImplementation
+ * @param adapterProperties
+ * @param propagate
+ */
+ public AdapterImpl(String factoryPid, String updateMethod, boolean propagate)
+ {
+ m_factoryPid = factoryPid;
+ m_update = updateMethod;
+ m_propagate = propagate;
+ }
+
+ /**
+ * Returns the managed service factory name.
+ */
+ public String getName()
+ {
+ return m_factoryPid;
+ }
+
+ /**
+ * Method called from our superclass, when we need to create a service.
+ */
+ public Service createService(Object[] properties) {
+ Dictionary settings = (Dictionary) properties[0];
+ Service newService = m_dm.createService();
+ Object impl = null;
+
+ try {
+ if (m_serviceImpl != null) {
+ impl = (m_serviceImpl instanceof Class) ?
+ ((Class) m_serviceImpl).newInstance() : m_serviceImpl;
+ } else {
+ impl = instantiateFromFactory(m_factory, m_factoryCreateMethod);
+ }
+ InvocationUtil.invokeCallbackMethod(impl, m_update,
+ new Class[][] {{ Dictionary.class }, {}},
+ new Object[][] {{ settings }, {}});
+ }
+
+ catch (Throwable t)
+ {
+ handleException(t);
+ }
+
+ // Merge adapter service properties, with CM settings
+ Dictionary serviceProperties = m_propagate ? mergeSettings(m_serviceProperties, settings) : m_serviceProperties;
+ newService.setInterface(m_serviceInterfaces, serviceProperties);
+ newService.setImplementation(impl);
+ List dependencies = m_service.getDependencies();
+ newService.add(dependencies);
+ newService.setComposition(m_compositionInstance, m_compositionMethod); // if not set, no effect
+ newService.setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy); // if not set, no effect
+ for (int i = 0; i < m_stateListeners.size(); i ++) {
+ newService.addStateListener((ServiceStateListener) m_stateListeners.get(i));
+ }
+
+ return newService;
+ }
+
+ /**
+ * Method called from our superclass, when we need to update a Service, because
+ * the configuration has changed.
+ */
+ public void updateService(Object[] properties)
+ {
+ Dictionary settings = (Dictionary) properties[0];
+ Service service = (Service) properties[1];
+ Object impl = service.getService();
+
+ try
+ {
+ InvocationUtil.invokeCallbackMethod(impl, m_update,
+ new Class[][] {{ Dictionary.class }, {}},
+ new Object[][] {{ settings }, {}});
+ if (m_serviceInterfaces != null && m_propagate == true) {
+ settings = mergeSettings(m_serviceProperties, settings);
+ service.setServiceProperties(settings);
+ }
+ }
+
+ catch (Throwable t)
+ {
+ handleException(t);
+ }
+ }
+
+ /**
+ * Merge CM factory configuration setting with the adapter service properties. The private CM factory configuration
+ * settings are ignored. A CM factory configuration property is private if its name starts with a dot (".").
+ *
+ * @param adapterProperties
+ * @param settings
+ * @return
+ */
+ private Dictionary mergeSettings(Dictionary adapterProperties, Dictionary settings)
+ {
+ Dictionary props = new Hashtable();
+
+ if (adapterProperties != null) {
+ Enumeration keys = adapterProperties.keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ Object val = adapterProperties.get(key);
+ props.put(key, val);
+ }
+ }
+
+ Enumeration keys = settings.keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ if (! key.toString().startsWith(".")) {
+ // public properties are propagated
+ Object val = settings.get(key);
+ props.put(key, val);
+ }
+ }
+ return props;
+ }
+
+ private Object instantiateFromFactory(Object mFactory, String mFactoryCreateMethod)
+ {
+ Object factory = null;
+ if (m_factory instanceof Class) {
+ try {
+ factory = createInstance((Class) m_factory);
+ }
+ catch (Throwable t) {
+ handleException(t);
+ }
+ }
+ else {
+ factory = m_factory;
+ }
+
+ try {
+ return InvocationUtil.invokeMethod(factory, factory.getClass(), m_factoryCreateMethod,
+ new Class[][] {{}}, new Object[][] {{}}, false);
+ }
+ catch (Throwable t) {
+ handleException(t);
+ return null;
+ }
+ }
+
+ private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
+ Constructor constructor = clazz.getConstructor(new Class[] {});
+ constructor.setAccessible(true);
+ return clazz.newInstance();
+ }
+
+ private void handleException(Throwable t) {
+ if (t instanceof InvocationTargetException)
+ {
+ // Our super class will check if the target exception is itself a ConfigurationException.
+ // In this case, it will simply re-thrown.
+ throw new RuntimeException(((InvocationTargetException) t).getTargetException());
+ } else if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else {
+ throw new RuntimeException(t);
+ }
+ }
+ }
+
+
+ /**
+ * Extends AdapterImpl for MetaType support.
+ */
+ class MetaTypeAdapterImpl extends AdapterImpl implements MetaTypeProvider {
+ // Our MetaType Provider for describing our properties metadata
+ private MetaTypeProviderImpl m_metaType;
+
+ public MetaTypeAdapterImpl(String factoryPid, String updateMethod, boolean propagate,
+ BundleContext bctx, Logger logger, String heading,
+ String description, String localization,
+ PropertyMetaData[] properyMetaData)
+ {
+ super(factoryPid, updateMethod, propagate);
+ m_metaType = new MetaTypeProviderImpl(m_factoryPid, bctx, logger, null, this);
+ m_metaType.setName(heading);
+ m_metaType.setDescription(description);
+ if (localization != null)
+ {
+ m_metaType.setLocalization(localization);
+ }
+ for (int i = 0; i < properyMetaData.length; i ++)
+ {
+ m_metaType.add(properyMetaData[i]);
+ }
+ }
+
+ public String[] getLocales()
+ {
+ return m_metaType.getLocales();
+ }
+
+ public ObjectClassDefinition getObjectClassDefinition(String id, String locale)
+ {
+ return m_metaType.getObjectClassDefinition(id, locale);
+ }
+ }
+}
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
index dc8ce75..b499dec 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
@@ -47,7 +47,9 @@
String[] services = serviceMetaData.getStrings(Params.service, null);
Dictionary<String, Object> properties = serviceMetaData.getDictionary(Params.properties, null);
boolean propagate = "true".equals(serviceMetaData.getString(Params.propagate, "false"));
- Service srv = dm.createFactoryConfigurationAdapterService(factoryPid, updated, impl, services, properties, propagate);
+ Service srv = dm.createFactoryConfigurationAdapterService(factoryPid, updated, propagate)
+ .setInterface(services, properties)
+ .setImplementation(impl);
setCommonServiceParams(srv, serviceMetaData);
for (MetaData dependencyMetaData: serviceDependencies)
{
diff --git a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
index 2429e63..1a05804 100644
--- a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
+++ b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/FactoryConfigurationAdapterTest.java
@@ -71,12 +71,10 @@
// Create an Adapter that will be instantiated, once the configuration is created.
// This Adapter provides an AdapterService, and depends on an AdapterExtraDependency service.
- Service s2 = m.createFactoryConfigurationAdapterService("MyFactoryPid",
- "updated",
- Adapter.class,
- AdapterService.class.getName(),
- new Properties() {{ put("foo", "bar"); }},
- true /* propagate CM settings */);
+ Service s2 = m.createFactoryConfigurationAdapterService("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)