Skip to content

Commit

Permalink
Merge pull request #814 from timothyjward/cfg/placeholder
Browse files Browse the repository at this point in the history
Support placeholders in configuration values
  • Loading branch information
timothyjward authored Feb 27, 2024
2 parents eb2d01d + 1231ae5 commit f2097fd
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,21 @@ public enum ValueSource {
TestUniqueId
}

/**
* Used to provide an argument in the {@link Property#templateArguments()}.
* {@link TemplateArgument} values are resolved in the same way as
* {@link Property} values but they are always of {@link Type#Scalar}
*
* @since 1.2
*/
public @interface TemplateArgument {
String[] value() default "";

Scalar scalar() default Scalar.String;

ValueSource source() default ValueSource.Value;
}

String key();

String[] value() default "";
Expand All @@ -105,4 +120,22 @@ public enum ValueSource {
*/
ValueSource source() default ValueSource.Value;

/**
* If any template arguments are set then the resolved value of this
* {@link Property} annotation will be used as a template in
* {@link String#format} with the resolved {@link TemplateArgument} values used
* as arguments.
* <p>
* Note that any defaulting or processing according to the {@link #source()}
* will happen <em>before</em> the formatting is applied, so template
* arguments cannot be used, for example, to change the name of a system
* property. Conversely, the scalar conversion will happen <em>after</em>
* the template is applied, meaning that numeric values can be assembled
* from multiple template arguments.
*
* @return the arguments that should be used with the template
* @since 1.2
*/
TemplateArgument[] templateArguments() default {};

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.osgi.test.common.annotation.Property;
import org.osgi.test.common.annotation.Property.Scalar;
import org.osgi.test.common.annotation.Property.Type;
import org.osgi.test.common.annotation.Property.ValueSource;

public class PropertiesConverter {

Expand All @@ -41,60 +42,19 @@ private static Object toValue(Description desc, Property entry) {

boolean primitive = entry.type()
.equals(Type.PrimitiveArray);
String[] value = getRawValue(desc, entry);
String[] value = getRawValue(desc, entry.value(), entry.source(), entry.type());

Object[] templateParams = Arrays.stream(entry.templateArguments())
.map(ta -> convertScalar(ta.scalar(), getRawValue(desc, ta.value(), ta.source(), Type.Scalar)[0]))
.toArray();

Object result = createArray(entry.scalar(), primitive, value.length);
int i = 0;
for (String v : value) {
Object val = null;

if (v != null) {
switch (entry.scalar()) {
case Boolean :
Boolean booleanValue = Boolean.valueOf(v);
val = primitive ? booleanValue.booleanValue() : booleanValue;
break;

case Byte :
Byte byteVal = Byte.valueOf(v);
val = primitive ? byteVal.byteValue() : byteVal;
break;

case Character :
char charVal = v.charAt(0);
val = primitive ? charVal : Character.valueOf(charVal);
break;

case Double :
Double doubleVal = Double.valueOf(v);
val = primitive ? doubleVal.doubleValue() : doubleVal;
break;

case Float :
Float floatVal = Float.valueOf(v);
val = primitive ? floatVal.floatValue() : floatVal;
break;

case Integer :
Integer integerVal = Integer.valueOf(v);
val = primitive ? integerVal.intValue() : integerVal;
break;

case Long :
Long longVal = Long.valueOf(v);
val = primitive ? longVal.longValue() : longVal;
break;

case Short :
Short shortVal = Short.valueOf(v);
val = primitive ? shortVal.shortValue() : shortVal;
break;

case String :
val = v;
break;
}
if (v != null && templateParams.length > 0) {
v = String.format(v, templateParams);
}
Object val = convertScalar(entry.scalar(), v);

if (Type.Scalar.equals(entry.type())) {
result = val;
Expand All @@ -119,10 +79,43 @@ private static Object toValue(Description desc, Property entry) {

}

private static String[] getRawValue(Description desc, Property entry) {
String[] value = entry.value();
private static Object convertScalar(Scalar scalar, String v) {
if (v != null) {
switch (scalar) {
case Boolean :
return Boolean.valueOf(v);

case Byte :
return Byte.valueOf(v);

case Character :
return v.charAt(0);

case Double :
return Double.valueOf(v);

case Float :
return Float.valueOf(v);

case Integer :
return Integer.valueOf(v);

case Long :
return Long.valueOf(v);

case Short :
return Short.valueOf(v);

case String :
return v;
}
}
return null;
}

private static String[] getRawValue(Description desc, String[] value, ValueSource source, Type type) {
String prop = null;
switch (entry.source()) {
switch (source) {
case EnvironmentVariable :
if (value.length == 0) {
throw new RuntimeException("A property name must be supplied for source EnvironmentVariable");
Expand Down Expand Up @@ -178,7 +171,7 @@ private static String[] getRawValue(Description desc, Property entry) {
throw new RuntimeException("conversion error - unknown source");
}

return entry.type() == Type.Scalar ? new String[] {
return type == Type.Scalar ? new String[] {
prop
} : prop.split("\\s*,\\s*");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
*
* @return The name
*/
String name();
String name() default Property.NOT_SET;

/**
* The location of the Configuration.<br>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
*******************************************************************************/

@org.osgi.annotation.bundle.Export
@org.osgi.annotation.versioning.Version("1.1.0")
@org.osgi.annotation.versioning.Version("1.1.1")

package org.osgi.test.common.annotation.config;
Original file line number Diff line number Diff line change
Expand Up @@ -185,25 +185,36 @@ private ConfigurationHolder handleWithFactoryConfiguration(ExtensionContext cont
WithFactoryConfiguration configAnnotation, ConfigurationAdmin configurationAdmin) {

try {
Configuration configBefore = ConfigUtil.getConfigsByServicePid(configurationAdmin,
configAnnotation.factoryPid() + "~" + configAnnotation.name(), 0l);
Configuration configBefore;
Configuration configuration;

Optional<ConfigurationCopy> copyOfBefore = createConfigurationCopy(configBefore);
if (Property.NOT_SET.equals(configAnnotation.name())) {
configBefore = null;

Configuration configuration;
if (Property.NOT_SET.equals(configAnnotation.location())) {
configuration = configurationAdmin.getFactoryConfiguration(configAnnotation.factoryPid(),
configAnnotation.name(), null);
if (Property.NOT_SET.equals(configAnnotation.location())) {
configuration = configurationAdmin.createFactoryConfiguration(configAnnotation.factoryPid(), null);
} else {
configuration = configurationAdmin.createFactoryConfiguration(configAnnotation.factoryPid(),
configAnnotation.location());
}
} else {
configuration = configurationAdmin.getFactoryConfiguration(configAnnotation.factoryPid(),
configAnnotation.name(), configAnnotation.location());
configBefore = ConfigUtil.getConfigsByServicePid(configurationAdmin,
configAnnotation.factoryPid() + "~" + configAnnotation.name(), 0l);

if (Property.NOT_SET.equals(configAnnotation.location())) {
configuration = configurationAdmin.getFactoryConfiguration(configAnnotation.factoryPid(),
configAnnotation.name(), null);
} else {
configuration = configurationAdmin.getFactoryConfiguration(configAnnotation.factoryPid(),
configAnnotation.name(), configAnnotation.location());
}
}

updateConfigurationRespectNew(context, configuration,
PropertiesConverter.of(context, configAnnotation.properties()),
configBefore == null);

return new ConfigurationHolder(ConfigurationCopy.of(configuration), copyOfBefore);
return new ConfigurationHolder(ConfigurationCopy.of(configuration), createConfigurationCopy(configBefore));
} catch (Exception e) {
throw new ParameterResolutionException(
String.format("Unable to obtain Configuration for %s.", configAnnotation.factoryPid()), e);
Expand Down
Loading

0 comments on commit f2097fd

Please sign in to comment.