Author: pderop
Date: Wed Feb 17 20:35:16 2016
New Revision: 1730934

URL: http://svn.apache.org/viewvc?rev=1730934&view=rev
Log:
FELIX-5177:

- added a configType attribute in FactoryConfigurationAdapterService annotation.
- when using a config type with ConfigurationDependency, then assume that pid 
is set to the fqdn of the provided config type, in case
no pid has already been set using setPid method.
- code cleanup.
- adapted samples to use configuration type.
- added javadocs.

Added:
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumerConf.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumerConf.java
Modified:
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/ConfigurationDependency.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/FactoryConfigurationAdapterService.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/DependencyBuilder.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/Params.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/hello.api.bnd
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/Activator.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/ConfigurationDependency.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/context/ComponentContext.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
    
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/ConfigurationDependency.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/ConfigurationDependency.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/ConfigurationDependency.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/ConfigurationDependency.java
 Wed Feb 17 20:35:16 2016
@@ -22,6 +22,9 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Map;
 
 
 /**
@@ -29,11 +32,21 @@ import java.lang.annotation.Target;
  * is always required, and allows you to depend on the availability of a valid 
configuration 
  * for your component. This dependency requires the OSGi Configuration Admin 
Service.
  * 
+ * The annotation can be applied on a callback method which accepts the 
following parameters:
+ * 
+ * <p><ul>
+ * <li>callback(Dictionary) 
+ * <li>callback(Component, Dictionary) 
+ * <li>callback(Configuration interface) // type safe configuration
+ * <li>callback(Component, Configuration interface) // type safe configuration
+ * </ul>
+ * 
  * <h3>Usage Examples</h3>
  * 
  * <p> In the following example, the "Printer" component depends on a 
configuration
  * whose PID name is "sample.PrinterConfiguration". This service will 
initialize
  * its ip/port number from the provided configuration.
+ * 
  * <p> First, we define the configuration metadata, using standard bndtools 
metatatype annotations 
  * (see http://www.aqute.biz/Bnd/MetaType):
  * 
@@ -63,10 +76,8 @@ import java.lang.annotation.Target;
  *
  * &#64;Component
  * public class Printer {
- *     &#64;ConfigurationDependency(pidClass = PrinterConfiguration.class) // 
Will use pid "sample.PrinterConfiguration"
- *     void updated(Dictionary props) {
- *         // load configuration from the provided dictionary, or throw an 
exception of any configuration error.
- *         PrinterConfig cnf = 
Configurable.createConfigurable(PrinterConfig.class, props);
+ *     &#64;ConfigurationDependency // Will use the fqdn of the  
PrinterConfiguration interface as the pid.
+ *     void updated(PrinterConfiguration cnf) {
  *         String ip = cnf.ipAddress();
  *         int port = cnf.portNumber();
  *         ...
@@ -75,6 +86,59 @@ import java.lang.annotation.Target;
  * </pre>
  * </blockquote>
  * 
+ * In the above example, the updated callback accepts a type-safe 
configuration type (and its fqdn is used as the pid).
+ * <p> Configuration type is a new feature that allows you to specify an 
interface that is implemented 
+ * by DM and such interface is then injected to your callback instead of the 
actual Dictionary.
+ * Using such configuration interface provides a way for creating type-safe 
configurations from a actual {@link Dictionary} that is
+ * normally injected by Dependency Manager.
+ * The callback accepts in argument an interface that you have to provide, and 
DM will inject a proxy that converts
+ * method calls from your configuration-type to lookups in the actual map or 
dictionary. The results of these lookups are then
+ * converted to the expected return type of the invoked configuration 
method.<br>
+ * As proxies are injected, no implementations of the desired 
configuration-type are necessary!
+ * </p>
+ * <p>
+ * The lookups performed are based on the name of the method called on the 
configuration type. The method names are
+ * "mangled" to the following form: <tt>[lower case letter] [any valid 
character]*</tt>. Method names starting with
+ * <tt>get</tt> or <tt>is</tt> (JavaBean convention) are stripped from these 
prefixes. For example: given a dictionary
+ * with the key <tt>"foo"</tt> can be accessed from a configuration-type using 
the following method names:
+ * <tt>foo()</tt>, <tt>getFoo()</tt> and <tt>isFoo()</tt>.
+ * </p>
+ * <p>
+ * The return values supported are: primitive types (or their object 
wrappers), strings, enums, arrays of
+ * primitives/strings, {@link Collection} types, {@link Map} types, {@link 
Class}es and interfaces. When an interface is
+ * returned, it is treated equally to a configuration type, that is, it is 
returned as a proxy.
+ * </p>
+ * <p>
+ * Arrays can be represented either as comma-separated values, optionally 
enclosed in square brackets. For example:
+ * <tt>[ a, b, c ]</tt> and <tt>a, b,c</tt> are both considered an array of 
length 3 with the values "a", "b" and "c".
+ * Alternatively, you can append the array index to the key in the dictionary 
to obtain the same: a dictionary with
+ * "arr.0" =&gt; "a", "arr.1" =&gt; "b", "arr.2" =&gt; "c" would result in the 
same array as the earlier examples.
+ * </p>
+ * <p>
+ * Maps can be represented as single string values similarly as arrays, each 
value consisting of both the key and value
+ * separated by a dot. Optionally, the value can be enclosed in curly 
brackets. Similar to array, you can use the same
+ * dot notation using the keys. For example, a dictionary with 
+ * 
+ * <pre>{@code "map" => "{key1.value1, key2.value2}"}</pre> 
+ * 
+ * and a dictionary with <p>
+ * 
+ * <pre>{@code "map.key1" => "value1", "map2.key2" => "value2"}</pre> 
+ * 
+ * result in the same map being returned.
+ * Instead of a map, you could also define an interface with the methods 
<tt>getKey1()</tt> and <tt>getKey2</tt> and use
+ * that interface as return type instead of a {@link Map}.
+ * </p>
+ * <p>
+ * In case a lookup does not yield a value from the underlying map or 
dictionary, the following rules are applied:
+ * <ol>
+ * <li>primitive types yield their default value, as defined by the Java 
Specification;
+ * <li>string, {@link Class}es and enum values yield <code>null</code>;
+ * <li>for arrays, collections and maps, an empty array/collection/map is 
returned;
+ * <li>for other interface types that are treated as configuration type a 
null-object is returned.
+ * </ol>
+ * </p>
+ * 
  * @author <a href="mailto:[email protected]";>Felix Project Team</a>
  */
 @Retention(RetentionPolicy.CLASS)
@@ -92,9 +156,10 @@ public @interface ConfigurationDependenc
      * You can use this method when you use an interface annotated with 
standard bndtols metatype annotations.
      * (see http://www.aqute.biz/Bnd/MetaType).
      * @return the pid class
+     * @deprecated just define an updated callback which accepts as argument a 
configuration type.
      */
     Class<?> pidClass() default Object.class;
-
+    
     /**
      * Returns true if the configuration properties must be published along 
with the service. 
      * Any additional service properties specified directly are merged with 
these.

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/FactoryConfigurationAdapterService.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/FactoryConfigurationAdapterService.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/FactoryConfigurationAdapterService.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/api/FactoryConfigurationAdapterService.java
 Wed Feb 17 20:35:16 2016
@@ -31,6 +31,13 @@ import java.lang.annotation.Target;
  * 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.
  * 
+ * <p> If you specify a configuration type, then the fqdn of the configuration 
interface is used as the factory pid,
+ * else you can specify the factory pid explicitly using the factoryPid 
attribute.
+ * If no configuration type is used and no factoryPid attribute is specified, 
then the factory pid will be set to the fqdn of
+ * the class on which this annotation is applied.
+ * 
+ * <p> (see javadoc from {@link ConfigurationDependency} for more informations 
about configuration types).
+ * 
  * <h3>Usage Examples</h3>
  * Here, a "Dictionary" service instance is created for each existing 
"sample.DictionaryConfiguration" factory pids.
  * 
@@ -55,19 +62,16 @@ import java.lang.annotation.Target;
  * </pre>
  * </blockquote>
  *
- * And here is the Dictionary service:
- *
+ * And here is the factory pid adapter service, which is instantiated for each 
instance of the "sample.DictionaryConfiguration" factory pid:
+ * 
  * <blockquote>
  * <pre>
  * import java.util.List;
  * import aQute.bnd.annotation.metatype.Configurable;
  *
- * 
&#64;FactoryConfigurationAdapterService(factoryPidClass=DictionaryConfiguration.class)
  
+ * 
&#64;FactoryConfigurationAdapterService(configType=DictionaryConfiguration.class)
  
  * public class DictionaryImpl implements DictionaryService {
- *     protected void updated(Dictionary&#60;String, ?&#62; props) {
- *         // load configuration from the provided dictionary, or throw an 
exception of any configuration error.
- *         DictionaryConfiguration cnf = 
Configurable.createConfigurable(DictionaryConfiguration.class, props);
- * 
+ *     protected void updated(DictionaryConfiguration config) {
  *         m_lang = config.lang();
  *         m_words.clear();
  *         for (String word : conf.words()) {
@@ -79,6 +83,7 @@ import java.lang.annotation.Target;
  * </pre>
  * </blockquote>
  * 
+ * 
  * @author <a href="mailto:[email protected]";>Felix Project Team</a>
  */
 @Retention(RetentionPolicy.CLASS)
@@ -100,6 +105,15 @@ public @interface FactoryConfigurationAd
     Property[] properties() default {};
 
     /**
+     * Returns the type safe configuration class which will be injected in the 
updated callback.
+     * By default, the factory pid is assumed to match the fqdn of the 
configuration type.
+     * see javadoc from {@link ConfigurationDependency} for more informations 
about configuration types.
+     * @return the configuration type to pass in the "updated" callback 
argument.
+     * @see ConfigurationDependency
+     */
+    Class<?> configType() default Object.class;
+    
+    /**
      * Returns the factory pid whose configurations will instantiate the 
annotated service class. (By default, the pid is the 
      * service class name).
      * @return the factory pid
@@ -111,6 +125,8 @@ public @interface FactoryConfigurationAd
      * You can use this method when you use an interface annoted with standard 
bndtols metatype annotations.
      * (see http://www.aqute.biz/Bnd/MetaType).
      * @return the factory pid class
+     * @deprecated use {@link #configType()} and accept a configuration type 
parameter from your updated callback. The pid
+     * is then assumed to match the fqdn of the configuration type.
      */
     Class<?> factoryPidClass() default Object.class;
 

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
 Wed Feb 17 20:35:16 2016
@@ -640,7 +640,7 @@ public class AnnotationCollector extends
             if (! Dictionary.class.getName().equals(confProxyType)) 
             {
                 // It's a conf proxy type.
-                writer.put(EntryParam.confProxyType, confProxyType);
+                writer.put(EntryParam.configType, confProxyType);
             }
             else
             {
@@ -655,7 +655,7 @@ public class AnnotationCollector extends
             if (! Dictionary.class.getName().equals(confProxyType)) 
             {
                 // It's a conf proxy type.
-                writer.put(EntryParam.confProxyType, confProxyType);
+                writer.put(EntryParam.configType, confProxyType);
             }
             else
             {
@@ -922,12 +922,19 @@ public class AnnotationCollector extends
         // factory pid attribute (can be specified using the factoryPid 
attribute, or using the factoryPidClass attribute)
         String factoryPidClass = 
parseClassAttrValue(annotation.get(EntryParam.factoryPidClass.toString()));
         
-        // If a factory pid class is specified, consider it as a possible 
candidate for a configuration proxy.
-        if (factoryPidClass != null) {
-            writer.put(EntryParam.confProxyType, factoryPidClass);
+        // Test if a type safe configuration type is provided.
+        String configType = 
parseClassAttrValue(annotation.get(EntryParam.configType.toString()));
+        
+        if (configType != null) {
+            writer.put(EntryParam.configType, configType);
         }
         
-        String factoryPid = factoryPidClass != null ? factoryPidClass : 
get(annotation, EntryParam.factoryPid.toString(), m_className);
+        String factoryPid = null;
+        
+        factoryPid = get(annotation, EntryParam.factoryPid.toString(), 
factoryPidClass);
+        if (factoryPid == null) {
+            factoryPid = configType != null ? configType : m_className;
+        }
         
         writer.put(EntryParam.factoryPid, factoryPid);
 

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.annotation/src/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
 Wed Feb 17 20:35:16 2016
@@ -44,7 +44,7 @@ public enum EntryParam
     autoConfig, 
     pid,
     pidClass,
-    confProxyType, // inject a proxy configuration type 
+    configType, // inject a proxy configuration type 
     factoryPid,
     factoryPidClass,
     propagate, 

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/DependencyBuilder.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/DependencyBuilder.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/DependencyBuilder.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/DependencyBuilder.java
 Wed Feb 17 20:35:16 2016
@@ -139,7 +139,7 @@ public class DependencyBuilder
 
     private Dependency createConfigurationDependency(Bundle b, 
DependencyManager dm) throws Exception
     {
-        String confProxyType = m_metaData.getString(Params.confProxyType, 
null);
+        String confProxyType = m_metaData.getString(Params.configType, null);
         String pid = m_metaData.getString(Params.pid);
         boolean propagate = 
"true".equals(m_metaData.getString(Params.propagate, "false"));
         String callback = m_metaData.getString(Params.updated, "updated");

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
 Wed Feb 17 20:35:16 2016
@@ -51,7 +51,7 @@ public class FactoryConfigurationAdapter
         String[] provides = srvMeta.getStrings(Params.provides, null);
         Dictionary<String, Object> properties = 
srvMeta.getDictionary(Params.properties, null);
         boolean propagate = "true".equals(srvMeta.getString(Params.propagate, 
"false"));
-        String configProxyClassName = srvMeta.getString(Params.confProxyType, 
null);
+        String configProxyClassName = srvMeta.getString(Params.configType, 
null);
         Component c = null;
         
         if (configProxyClassName != null)

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/Params.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/Params.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/Params.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.runtime/src/org/apache/felix/dm/runtime/Params.java
 Wed Feb 17 20:35:16 2016
@@ -65,5 +65,5 @@ public enum Params
     componentField,
     registered, 
     unregistered,
-    confProxyType
+    configType
 }

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/hello.api.bnd
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/hello.api.bnd?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/hello.api.bnd
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/hello.api.bnd
 Wed Feb 17 20:35:16 2016
@@ -14,8 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-Private-Package:  \
-       org.apache.felix.dependencymanager.samples.hello.api
 Bundle-Activator: 
org.apache.felix.dependencymanager.samples.hello.api.Activator
 Bundle-Description: Dependency Manager hello example with API
-Bundle-Name: Dependency Manager Hello Example
\ No newline at end of file
+Bundle-Name: Dependency Manager Hello Example
+Private-Package: org.apache.felix.dependencymanager.samples.hello.api
\ No newline at end of file

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/conf/Configurator.java
 Wed Feb 17 20:35:16 2016
@@ -21,6 +21,7 @@ package org.apache.felix.dependencymanag
 import java.io.IOException;
 import java.util.Hashtable;
 
+import 
org.apache.felix.dependencymanager.samples.hello.api.ServiceConsumerConf;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.log.LogService;
@@ -41,13 +42,13 @@ public class Configurator {
             System.out.println("Configuring sample components ... please 
consult log messages to see example output, like this:");
             System.out.println("\"log warn\"");
             // Provide configuration to the hello.ServiceConsumer component
-            m_serviceConsumerConf = 
m_ca.getConfiguration("org.apache.felix.dependencymanager.samples.hello.api.ServiceConsumer",
 null);
+            m_serviceConsumerConf = 
m_ca.getConfiguration("org.apache.felix.dependencymanager.samples.hello.api.ServiceConsumerConf",
 null);
             Hashtable<String, String> props = new Hashtable<>();
             props.put("key", "value");
             m_serviceConsumerConf.update(props);
             
             // Provide configuration to the hello.annot.ServiceConsumer 
component
-            m_serviceConsumerAnnotConf = 
m_ca.getConfiguration("org.apache.felix.dependencymanager.samples.hello.annot.ServiceConsumer",
 null);
+            m_serviceConsumerAnnotConf = 
m_ca.getConfiguration("org.apache.felix.dependencymanager.samples.hello.annot.ServiceConsumerConf",
 null);
             props = new Hashtable<>();
             props.put("key", "value");
             m_serviceConsumerAnnotConf.update(props);

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumer.java
 Wed Feb 17 20:35:16 2016
@@ -39,15 +39,16 @@ public class ServiceConsumer {
     @ServiceDependency
     volatile LogService log;
 
-    Dictionary<?, ?> conf;
+    ServiceConsumerConf conf;
 
-    @ConfigurationDependency
-    protected void update(Dictionary<?, ?> conf) {
+    @ConfigurationDependency 
+    protected void update(ServiceConsumerConf conf) { // type safe config
         this.conf = conf;
     }
 
     @Start
     public void start() {
+        log.log(LogService.LOG_WARNING, "ServiceConsumer.start: configured 
key=" + conf.getKey());
         log.log(LogService.LOG_WARNING, "ServiceConsumer.start: calling 
service.hello() ...");
         this.service.hello();
     }

Added: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumerConf.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumerConf.java?rev=1730934&view=auto
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumerConf.java
 (added)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/annot/ServiceConsumerConf.java
 Wed Feb 17 20:35:16 2016
@@ -0,0 +1,28 @@
+/*
+ * 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.dependencymanager.samples.hello.annot;
+
+/**
+ * This is our type-safe configuration for the ServiceConsumer component.
+ * 
+ * @author <a href="mailto:[email protected]";>Felix Project Team</a>
+ */
+public interface ServiceConsumerConf {
+    String getKey();
+}

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/Activator.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/Activator.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/Activator.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/Activator.java
 Wed Feb 17 20:35:16 2016
@@ -37,8 +37,7 @@ public class Activator extends Dependenc
         dm.add(createComponent()
             .setImplementation(ServiceConsumer.class)            
             
.add(createServiceDependency().setService(LogService.class).setRequired(true))
-            .add(createConfigurationDependency()
-                
.setPid(ServiceConsumer.class.getName()).setCallback("updated"))
+            .add(createConfigurationDependency().setCallback("updated", 
ServiceConsumerConf.class))
             
.add(createServiceDependency().setService(ServiceProvider.class).setRequired(true)));
     }
 }

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumer.java
 Wed Feb 17 20:35:16 2016
@@ -30,13 +30,14 @@ import org.osgi.service.log.LogService;
 public class ServiceConsumer {
     volatile ServiceProvider service;
     volatile LogService log;
-    Dictionary<?, ?> conf;
-
-    protected void update(Dictionary<?, ?> conf) {
+    ServiceConsumerConf conf;
+    
+    protected void updated(ServiceConsumerConf conf) {
         this.conf = conf;
     }
 
     public void start() {
+        log.log(LogService.LOG_WARNING, "ServiceConsumer.start: configured key 
= " + conf.getKey());
         log.log(LogService.LOG_WARNING, "ServiceConsumer.start: calling 
service.hello()");
         this.service.hello();
     }

Added: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumerConf.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumerConf.java?rev=1730934&view=auto
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumerConf.java
 (added)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/hello/api/ServiceConsumerConf.java
 Wed Feb 17 20:35:16 2016
@@ -0,0 +1,28 @@
+/*
+ * 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.dependencymanager.samples.hello.api;
+
+/**
+ * This is our type-safe configuration for the ServiceConsumer component.
+ * 
+ * @author <a href="mailto:[email protected]";>Felix Project Team</a>
+ */
+public interface ServiceConsumerConf {
+    String getKey();
+}

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/ConfigurationDependency.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/ConfigurationDependency.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/ConfigurationDependency.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/ConfigurationDependency.java
 Wed Feb 17 20:35:16 2016
@@ -18,6 +18,10 @@
  */
 package org.apache.felix.dm;
 
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Map;
+
 import aQute.bnd.annotation.ProviderType;
 
 /**
@@ -48,8 +52,61 @@ import aQute.bnd.annotation.ProviderType
  * The callback invoked when a configuration dependency is updated can 
supports the following signatures:<p>
  * <ul><li> updated(Dictionary)
  *     <li> updated(Component, Dictionary)
+ *     <li> updated(Configuration interface)
+ *     <li> updated(Component, Configuration interface)
  * </ul>
  * 
+ * <p> Configuration interface is a new feature that allows you to specify an 
interface that is implemented 
+ * by DM and such interface is then injected to your callback instead of the 
actual Dictionary.
+ * Using such configuration interface provides a way for creating type-safe 
configurations from a actual {@link Dictionary} that is
+ * normally injected by Dependency Manager.
+ * The callback accepts in argument an interface that you have to provide, and 
DM will inject a proxy that converts
+ * method calls from your configuration-type to lookups in the actual map or 
dictionary. The results of these lookups are then
+ * converted to the expected return type of the invoked configuration 
method.<br>
+ * As proxies are injected, no implementations of the desired 
configuration-type are necessary!
+ * </p>
+ * <p>
+ * The lookups performed are based on the name of the method called on the 
configuration type. The method names are
+ * "mangled" to the following form: <tt>[lower case letter] [any valid 
character]*</tt>. Method names starting with
+ * <tt>get</tt> or <tt>is</tt> (JavaBean convention) are stripped from these 
prefixes. For example: given a dictionary
+ * with the key <tt>"foo"</tt> can be accessed from a configuration-type using 
the following method names:
+ * <tt>foo()</tt>, <tt>getFoo()</tt> and <tt>isFoo()</tt>.
+ * </p>
+ * <p>
+ * The return values supported are: primitive types (or their object 
wrappers), strings, enums, arrays of
+ * primitives/strings, {@link Collection} types, {@link Map} types, {@link 
Class}es and interfaces. When an interface is
+ * returned, it is treated equally to a configuration type, that is, it is 
returned as a proxy.
+ * </p>
+ * <p>
+ * Arrays can be represented either as comma-separated values, optionally 
enclosed in square brackets. For example:
+ * <tt>[ a, b, c ]</tt> and <tt>a, b,c</tt> are both considered an array of 
length 3 with the values "a", "b" and "c".
+ * Alternatively, you can append the array index to the key in the dictionary 
to obtain the same: a dictionary with
+ * "arr.0" =&gt; "a", "arr.1" =&gt; "b", "arr.2" =&gt; "c" would result in the 
same array as the earlier examples.
+ * </p>
+ * <p>
+ * Maps can be represented as single string values similarly as arrays, each 
value consisting of both the key and value
+ * separated by a dot. Optionally, the value can be enclosed in curly 
brackets. Similar to array, you can use the same
+ * dot notation using the keys. For example, a dictionary with 
+ * 
+ * <pre>{@code "map" => "{key1.value1, key2.value2}"}</pre> 
+ * 
+ * and a dictionary with <p>
+ * 
+ * <pre>{@code "map.key1" => "value1", "map2.key2" => "value2"}</pre> 
+ * 
+ * result in the same map being returned.
+ * Instead of a map, you could also define an interface with the methods 
<tt>getKey1()</tt> and <tt>getKey2</tt> and use
+ * that interface as return type instead of a {@link Map}.
+ * </p>
+ * <p>
+ * In case a lookup does not yield a value from the underlying map or 
dictionary, the following rules are applied:
+ * <ol>
+ * <li>primitive types yield their default value, as defined by the Java 
Specification;
+ * <li>string, {@link Class}es and enum values yield <code>null</code>;
+ * <li>for arrays, collections and maps, an empty array/collection/map is 
returned;
+ * <li>for other interface types that are treated as configuration type a 
null-object is returned.
+ * </ol>
+ * </p>
  * @author <a href="mailto:[email protected]";>Felix Project Team</a>
  */
 @ProviderType
@@ -98,6 +155,7 @@ public interface ConfigurationDependency
      * is available. The contract for this method is identical to that of
      * <code>ManagedService.updated(Dictionary) throws 
ConfigurationException</code> with the difference that 
      * instead of a Dictionary it accepts an interface of the given 
configuration type.<br>
+     * By default, the pid is assumed to match the fqdn of the configuration 
type.
      * 
      * <p>The callback is invoked on the instantiated component.
      * 

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
 Wed Feb 17 20:35:16 2016
@@ -467,8 +467,10 @@ public class DependencyManager {
      *        <li> updated(Component, Dictionary)
      *        </ul>
      * @param propagate true if public factory configuration should be 
propagated to the adapter service properties
-     * @param configType the configuration type to use instead of a dictionary 
or map.
+     * @param configType the configuration type to use instead of a 
dictionary. See the javadoc from {@link ConfigurationDependency} for
+     * more informations about type-safe configuration.
      * @return a service that acts as a factory for generating the managed 
service factory configuration adapter
+     * @see ConfigurationDependency
      */
     public Component createFactoryConfigurationAdapterService(String 
factoryPid, String update, boolean propagate, Class<?> configType) {
         return new FactoryConfigurationAdapterImpl(this, factoryPid, update, 
propagate, null, configType);
@@ -491,7 +493,8 @@ public class DependencyManager {
      *        </ul>
      * @param propagate true if public factory configuration should be 
propagated to the adapter service properties
      * @param callbackInstance the object on which the updated callback will 
be invoked.
-     * @param configType the configuration type to use instead of a dictionary 
or map.
+     * @param configType the configuration type to use instead of a 
dictionary.  See the javadoc from {@link ConfigurationDependency} for
+     * more informations about type-safe configuration.
      * @return a service that acts as a factory for generating the managed 
service factory configuration adapter
      */
     public Component createFactoryConfigurationAdapterService(String 
factoryPid, String update, boolean propagate, Object callbackInstance, Class<?> 
configType) {

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/context/ComponentContext.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/context/ComponentContext.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/context/ComponentContext.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/context/ComponentContext.java
 Wed Feb 17 20:35:16 2016
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.dm.context;
 
+import java.util.Dictionary;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Executor;
@@ -156,4 +157,15 @@ public interface ComponentContext extend
      * @return all the available dependency services for a given dependency
      */
     public Set<Event> getDependencyEvents(DependencyContext dc);
+    
+    /**
+     * Creates a configuration for a given type backed by a given dictionary.
+     * This method can be used by any custom Dependency Manager dependency that
+     * needs to expose some configuration through a dynamic proxy interface.
+     * 
+     * @param type the configuration class, cannot be <code>null</code>;
+     * @param config the configuration to wrap, cannot be <code>null</code>.
+     * @return an instance of the given type that wraps the given 
configuration.
+     */
+    public <T> T createConfigurationProxy(Class<T> type, Dictionary<?, ?> 
config);
 }

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java
 Wed Feb 17 20:35:16 2016
@@ -341,6 +341,11 @@ public class ComponentImpl implements Co
     }
 
     @Override
+    public <T> T createConfigurationProxy(Class<T> type, Dictionary<?, ?> 
config) {
+        return Configurable.create(type,  config);
+    }
+    
+    @Override
     public Executor getExecutor() {
         return m_executor;
     }

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
 Wed Feb 17 20:35:16 2016
@@ -21,6 +21,7 @@ package org.apache.felix.dm.impl;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Arrays;
 import java.util.Dictionary;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -126,8 +127,10 @@ public class ConfigurationDependencyImpl
      * Sets a type-safe callback method invoked on the instantiated component.
      */
     public ConfigurationDependency setCallback(String callback, Class<?> 
configType) {
+        Objects.nonNull(configType);
         setCallback(callback);
         m_configType = configType;
+        m_pid = (m_pid == null) ? configType.getName() : m_pid;
         return this;
     }
 
@@ -136,8 +139,10 @@ public class ConfigurationDependencyImpl
      * The component is not yet instantiated at the time the callback is 
invoked.
      */
     public ConfigurationDependency setCallback(Object instance, String 
callback, Class<?> configType) {
+        Objects.nonNull(configType);
         setCallback(instance, callback);
         m_configType = configType;
+        m_pid = (m_pid == null) ? configType.getName() : m_pid;
         return this;
     }
     

Modified: 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java?rev=1730934&r1=1730933&r2=1730934&view=diff
==============================================================================
--- 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java
 (original)
+++ 
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java
 Wed Feb 17 20:35:16 2016
@@ -67,6 +67,11 @@ public class FilterComponent implements
     }
     
     @Override
+    public <T> T createConfigurationProxy(Class<T> type, Dictionary<?, ?> 
config) {
+        return m_component.createConfigurationProxy(type, config);
+    }
+    
+    @Override
     public Executor getExecutor() {
         return m_component.getExecutor();
     }



Reply via email to