Author: pderop
Date: Sun Nov 6 23:32:02 2016
New Revision: 1768405
URL: http://svn.apache.org/viewvc?rev=1768405&view=rev
Log:
FELIX-5355: Allow to use properties having dots with configuration proxies.
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.lambda/src/org/apache/felix/dm/lambda/ConfigurationDependencyBuilder.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/impl/Configurable.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=1768405&r1=1768404&r2=1768405&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
Sun Nov 6 23:32:02 2016
@@ -59,10 +59,10 @@ import java.util.Map;
* @OCD(description = "Declare here the Printer Configuration.")
* public interface PrinterConfiguration {
* @AD(description = "Enter the printer ip address")
- * String ipAddress();
+ * String getAddress();
*
* @AD(description = "Enter the printer address port number.")
- * default int portNumber() { return 8080; }
+ * default int getPort() { return 8080; }
* }
* </pre>
* </blockquote>
@@ -78,8 +78,8 @@ import java.util.Map;
* public class Printer {
* @ConfigurationDependency // Will use the fqdn of the
PrinterConfiguration interface as the pid.
* void updated(PrinterConfiguration cnf) {
- * String ip = cnf.ipAddress();
- * int port = cnf.portNumber();
+ * String ip = cnf.getAddress();
+ * int port = cnf.getPort();
* ...
* }
* }
@@ -101,8 +101,18 @@ import java.util.Map;
* "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>
+ * <tt>foo()</tt>, <tt>getFoo()</tt> and <tt>isFoo()</tt>.<p>
+ * If the property contains a dot (which is invalid in java method names),
then dots (".") can be converted using the following conventions:
+ * <ul>
+ *
+ * <li> if the method name follows the javabean convention and/or kamel casing
convention, then each capital letter is assumed to map to a "dot",
+ * followed by the same letter in lower case. This means only lower case
properties are
+ * supported in this case. Example: getFooBar() or fooBar() will map to
"foo.bar" property.
+ *
+ * <li> else, if the method name follows the standard OSGi metatype
specification, then dots
+ * are encoded as "_"; and "_" is encoded as "__". (see OSGi r6 compendium,
chapter 105.9.2).
+ * Example: "foo_BAR()" is mapped to "foo.BAR" property; "foo__BAR_zoo()" is
mapped to "foo_BAR.zoo" property.
+ * </ul>
* <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
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ConfigurationDependencyBuilder.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ConfigurationDependencyBuilder.java?rev=1768405&r1=1768404&r2=1768405&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ConfigurationDependencyBuilder.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ConfigurationDependencyBuilder.java
Sun Nov 6 23:32:02 2016
@@ -62,8 +62,18 @@ import org.osgi.annotation.versioning.Pr
* "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>
+ * <tt>foo()</tt>, <tt>getFoo()</tt> and <tt>isFoo()</tt>.<p>
+ * If the property contains a dot (which is invalid in java method names),
then dots (".") can be converted using the following conventions:
+ * <ul>
+ *
+ * <li> if the method name follows the javabean convention and/or kamel casing
convention, then each capital letter is assumed to map to a "dot",
+ * followed by the same letter in lower case. This means only lower case
properties are
+ * supported in this case. Example: getFooBar() or fooBar() will map to
"foo.bar" property.
+ *
+ * <li> else, if the method name follows the standard OSGi metatype
specification, then dots
+ * are encoded as "_"; and "_" is encoded as "__". (see OSGi r6 compendium,
chapter 105.9.2).
+ * Example: "foo_BAR()" is mapped to "foo.BAR" property; "foo__BAR_zoo()" is
mapped to "foo_BAR.zoo" property.
+ * </ul>
* <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
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=1768405&r1=1768404&r2=1768405&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
Sun Nov 6 23:32:02 2016
@@ -69,8 +69,19 @@ import aQute.bnd.annotation.ProviderType
* "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>
+ * <tt>foo()</tt>, <tt>getFoo()</tt> and <tt>isFoo()</tt>.<p>
+ *
+ * If the property contains a dot (which is invalid in java method names),
then dots (".") can be converted using the following conventions:
+ * <ul>
+ *
+ * <li> if the method name follows the javabean convention and/or kamel casing
convention, then each capital letter is assumed to map to a "dot",
+ * followed by the same letter in lower case. This means only lower case
properties are
+ * supported in this case. Example: getFooBar() or fooBar() will map to
"foo.bar" property.
+ *
+ * <li> else, if the method name follows the standard OSGi metatype
specification, then dots
+ * are encoded as "_"; and "_" is encoded as "__". (see OSGi r6 compendium,
chapter 105.9.2).
+ * Example: "foo_BAR()" is mapped to "foo.BAR" property; "foo__BAR_zoo()" is
mapped to "foo_BAR.zoo" property.
+ * </ul>
* <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
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java?rev=1768405&r1=1768404&r2=1768405&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Configurable.java
Sun Nov 6 23:32:02 2016
@@ -59,6 +59,15 @@ import java.util.TreeSet;
* <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>.
+ *
+ * If the property name contains some dots, the the following conventions are
used:
+ * <ul>
+ * <li>camel casing: if a property contains multiple words separated by dots,
then you can indicate words boundaries using medial capitalization.
+ * For example, the property "foo.bar" could be accessed with a method name
like "fooBar()" or "getFooBar()".
+ * <li> use underscore to wrap dots: underscore ("_") found in method names
are converted to ".", unless they are followed by another underscore.
+ * (in this case, the double "__" is then converted to single underscore ("_").
+ * For Example: foo_bar() will be mapped to "foo.bar" property, and foo__bar()
will be mapped to "foo_bar" property.
+ * </ul>
* </p>
* <p>
* The return values supported are: primitive types (or their object
wrappers), strings, enums, arrays of
@@ -437,21 +446,119 @@ public final class Configurable {
return result;
}
-
- private String getPropertyName(String id) {
- StringBuilder sb = new StringBuilder(id);
- if (id.startsWith("get")) {
+
+ private String getPropertyName(String methodName) {
+ // First, derive the property name from the method name, using
simple javabean convention.
+ // i.e: fooBar() or getFooBar() will map to "fooBar" property.
+
+ String javaBeanMethodName =
derivePropertyNameUsingJavaBeanConvention(methodName);
+ if (hasValueFor(javaBeanMethodName)) {
+ // there is a value in the actual configuration for the
derived property name.
+ return javaBeanMethodName;
+ }
+
+ // Derive the property name from the method name, using javabeans
and/or camel casing convention,
+ // where each capital letter is assumed to map a "dot".
+ // i.e: fooBar() or getFooBar() will map to "foo.bar" property.
+
+ String camelCasePropertyName =
derivePropertyNameUsingCamelCaseConvention(javaBeanMethodName);
+ if (hasValueFor(camelCasePropertyName)) {
+ // there is a value in the actual configuration for the
derived property name.
+ return camelCasePropertyName;
+ }
+
+ // Derive the property name from the method name, using OSGi
metatype convention,
+ // where a "_" is mapped to a dot, except if the understcore is
followed by another undescore
+ // (in this case, the double "__" is replaced by "_").
+ // i.e: foo_bar() will map to "foo.bar" property and foo__bar()
will map to "foo_bar" property.
+
+ String metaTypePropertyName =
derivePropertyNameUsingMetaTypeConvention(methodName);
+ if (hasValueFor(metaTypePropertyName)) {
+ // there is a value in the actual configuration for the
derived property name.
+ return metaTypePropertyName;
+ }
+
+ // No value could be found, return by default a property name
derived from javabean convention.
+ return javaBeanMethodName;
+ }
+
+ private String derivePropertyNameUsingJavaBeanConvention(String
methodName) {
+ StringBuilder sb = new StringBuilder(methodName);
+
+ if (methodName.startsWith("get")) {
sb.delete(0, 3);
- }
- else if (id.startsWith("is")) {
+ } else if (methodName.startsWith("is")) {
sb.delete(0, 2);
}
+
char c = sb.charAt(0);
if (Character.isUpperCase(c)) {
sb.setCharAt(0, Character.toLowerCase(c));
}
+
+ return (sb.toString());
+ }
+
+ private String derivePropertyNameUsingCamelCaseConvention(String
methodName) {
+ StringBuilder sb = new StringBuilder(methodName);
+ for (int i = 0; i < sb.length(); i++) {
+ char c = sb.charAt(i);
+ if (Character.isUpperCase(c)) {
+ // camel casing: replace fooBar -> foo.bar
+ sb.setCharAt(i, Character.toLowerCase(c));
+ sb.insert(i, ".");
+ }
+ }
+ return sb.toString();
+ }
+
+ // see metatype spec, chapter 105.9.2 in osgi r6 cmpn.
+ private String derivePropertyNameUsingMetaTypeConvention(String
methodName) {
+ StringBuilder sb = new StringBuilder(methodName);
+ // replace "__" by "_" or "_" by ".": foo_bar -> foo.bar;
foo__BAR_zoo -> foo_BAR.zoo
+ for (int i = 0; i < sb.length(); i ++) {
+ if (sb.charAt(i) == '_') {
+ if (i < (sb.length() - 1) && sb.charAt(i+1) == '_') {
+ // replace foo__bar -> foo_bar
+ sb.replace(i, i+2, "_");
+ } else {
+ // replace foo_bar -> foo.bar
+ sb.replace(i, i+1, ".");
+ }
+ } else if (sb.charAt(i) == '$') {
+ if (i < (sb.length() - 1) && sb.charAt(i+1) == '$') {
+ // replace foo__bar -> foo_bar
+ sb.replace(i, i+2, "$");
+ } else {
+ // remove single dollar character.
+ sb.delete(i, i+1);
+ }
+ }
+ }
return sb.toString();
}
+
+ /**
+ * Checks if a property name has a given value. This method takes care
about special array values (arr.0, arr.1,...)
+ * and about map values (map.key1, map.key2, ...).
+ *
+ * @param property name
+ * @return true if the given property has a value in the actual
configuration, false if not.
+ */
+ private boolean hasValueFor(String property)
+ {
+ if (m_config.containsKey(property)) {
+ return true;
+ }
+ String needle = property.concat(".");
+ for (Map.Entry<?, ?> entry : m_config.entrySet()) {
+ String key = entry.getKey().toString();
+ if (key.startsWith(needle)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE;