This guide provides Information about the Initial Configuration Loader which is part of the Configuration Admin. Its implementation is described Using the Initial Configuration Loader in Azure IoT Integration module.
Configuration Model
Configurations are loaded from properties files which replace the old xml files. This scheme provides more flexibility and is less error-prone. The properties files are bound by the following rules:
Configuration Properties Files
The properties files follow the standard format, described in ATG Programming Guide.
By default only values of string type are supported. However there is support for all valid configuration value types if version 2 is enabled. All files, that use version 2, must include
# version = 2.0
at the beginning of the file. Supported types are boolean, byte, short, int, char, double, float, long, as well as arrays and lists of these types.
Here is a sample with a typical usage of a version 2.0 file:
# version = 2.0
i:Int=24
bool:boolean=false
byte:byte=4
s:Short=6
l:long=123456789654
f:float=3.14
d:Double=2.71
c:character=o
arr_i:int[]=2, 4
arr_bool:boolean[]=true,false
arr_byte1:byte[]=2,3,4
arr_s1:short[]=6
arr_l1:long[]=123456789654, 4242424242
arr_f1:float[]=3.14,3.0,4.0
arr_d1:double[]=2.71,-1.0
arr_c1:char[]=Only,t,e,s,t
arr_emp:int[0]=
col_i1:List<Int>=2, 4
col_i2:List<Integer>=7, 8
col_bool:List<boolean>=true,false
col_byte:List<byte>=2,3,4
col_s:List<Short>=6
col_l:List<long>=123456789654, 4242424242
col_f:List<float>=3.14,3.0,4.0
col_d:List<Double>=2.71,-1.0
col_c1:List<character>=Only,t,e,s,t
col_c2:List<Char>=Only,t,e,s,t
col_c3:List<char>= ,a , a
s1:String=test
s2:String=a,b,c
s3:String[]=test\,escaping,here
Configuration Binding
Created configurations may be bound to specific bundles. This requires using of version 3.0 at least. Binding locations are specified via bundle header. For example:
# version = 3.0
# bundle = com.prosyst.mbs.osgi.log.bundle
This guarantees that configuration will be bound to a bundle with the same symbolic name or location, when such bundle is installed.
Please have in mind, that the configuration may not occur at startup.
Each time a matching bundle is installed, there are two options:
# version = 3.1
# bundle = ...
# reload = false
Global Configuration Properties
Globally defined configuration properties are supported in configuration model. In order to use this feature, the user MUST define properties in a separate file in two ways:
Properties defined in a global configuration file are taken with precedence over those defined by standard properties files/metatype xml files. This means that any values defined in the standard files can be overwritten with the values of the global configuration properties.
The global configuration properties file follows a simple format, in which each not empty or comment line describes single configuration property. All valid configuration property types are supported.
<configuration pid>:<property key>(:<property type>)?=<property value> # applied for a single configuration with this pid
<configuration factory pid>:<property key>(:<property type>)?=<property value> # applied for all configurations with this factory pid
For example:
pid1:a:long=325235235236236
pid1:c=global
fpid1:x:int=10
fpid1:y:int=15
The configuration property values are injected at the moment configurations are created.
Parametrization of configuration properties files
Requirements
The user must be able to provide generic configuration property values in properties file used by the Initial Configuration Loader. This abstraction allows more flexibility and reusability than using a raw values.
There must be an option to use parameters in configuration files, which will be replaced with their values. Supported sources of parameter lookup are:
Solution
In order to use this functionality, following syntax is introduced in configuration properties files:
key=*${<parameter>}*
Values may have multiple parameters specified. On configuration loading, each parameter is replaced with its value – either an environment variable, system property or a property within the same configuration, if possible. If there is no possible replacement, property value is used as it is.
This syntax does not apply for property keys and values of non-string types.
Examples and javadoc
Some examples and link to official javadoc can be found here. The examples also work with configuration properties.
A known limitation is that properties cannot be applied as parameters between configurations.
Profiles
The configuration model supports different profiles of configurations. A profile is represented by a set of independent configurations. Each profile is contained in its own folder on the upper–most level of the config folder, corresponding to its name. For examples refer to Using the Initial Configuration Loader in Azure IoT Integration module.
Profiles are passed through the com.prosyst.mbs.osgi.cm.config.profiles – this system property is described in OSGi Configuration Loader Bundle, which provides it and has the following format:
profile1[, profile2, ..., profileN]
Profiles can not be edited at runtime.
Common Profiles
A Common Profile is provided. If a folder named common exist in the config directory, then all of its configurations are loaded, regardless of system property values. Each Profile contains either a properties files describing a configuration PID or folders describing a factory PID – FPID. Refer to Using the Initial Configuration Loader guide for the examples provided in Azure IoT Integration module.
Search Path
In some cases Profiles may contain overlapping key: value pairs. This type of conflicts are resolved by prioritizing the profiles according to the order in which they ware specified in the system property. For example if we have the following system property:
profile1[, profile2, profile3]
Profile3 have the lowest priority and Profile1, the highest. This means that any profile is able to overwrite a property loaded from profile3, and profile1 can overwrite any properties set by the other profiles.
The Common Profile has the lowest priority, regardless of its position inside the system property.
Polling for Changes
The loader may support periodical polling of the configuration data for changes. It is not enabled by default. If enabled profile configuration files are scanned periodically for changes and associated configurations are updated. Polling period is specified through system property com.prosyst.mbs.cm.polling.period (number of milliseconds). Giving a positive value enables polling for changes.
Example
File Structure
The Configurations folder may have the following structure:
config/common/pid.properties
config/common/fpid/$NAME.properties
config/profile-name1/pid.properties
config/profile-name1/fpid/$NAME.properties
...
config/profile-nameN/pid.properties
config/profile-nameN/fpid/$NAME1.properties
config/profile-nameN/fpid/$NAME2.properties
config/profile-nameN/fpid/$NAME3.properties
The last profile have one standard configuration and three factory configurations with factory pid fpid. $NAME1, $NAME2, $NAME3 are associated with pids generated for them.
For more examples refer to Using the Initial Configuration Loader in Azure IoT Integration module.
Annotated Interface
To create a Configuration new Java interface must be defined and annotated.
import com.prosyst.mbs.services.metatype.annotations.*;
import com.prosyst.mbs.services.metatype.annotations.Meta.Type;
@Meta.OCD(name = "Testing service config")
public interface MyConfig extends org.osgi.service.cm.ManagedService{
@Meta.AD(cardinality = 0, deflt = "test1", description = "Test String value", //
optionValues = { "test1", "test2"}, optionLabels = { "test1_label", "test2_label"})
public String stringProperty();
@Meta.AD(cardinality = 0, name = "Integer Property", description = "Test int value", min = "2", max = "5")
public int intProperty();
// default cardinality = 0
@Meta.AD(deflt = "3", min = "2", max = "5", name = "Test Integer value")
public Integer wrapperIntProperty();
}
The annotations support all types defined by the OSGi specification. For more information refer to the Metatype Annotations Demo or the BND Metatype Documentation.
Using the Configuration
To create an instance of the configuration interface add the following code:
import com.prosyst.mbs.services.metatype.annotations.Configurable;
.....
MyConfig myConfig = Configurable.createConfigurable(MyConfig.class, (Map<?, ?>) null);
int data = myConfig.intProperty();
The above code creates an initial configuration file filled-in with the default values. If there are properties with no default values, the above code properly will fail, because it will not validate properly.
To register the created instance, create a ManagedService implementation. Within it, call the updated() method of the configuration. After the configuration has been updated the changes will be applied. For example restart the TCP/IP server and bind it to the newly configured port.
The example below illustrates the recommended usage scenario:
....
reg = context.registerService(ManagedService.class, this, props);
public void updated(Dictionary< String, ?> properties) throws ConfigurationException {
// update the configuration object
int oldPort = myConfig.intProperty();
myConfig.updated(properties);
if (oldPort != myConfig.intProperty()) {
// TODO: restart the TCP server
} // else the other changes will be applied automatically without restart, starting from next connected client
}
For more information refer to the Metatype Annotations Demo.
Generated Resources
Running
From Javac
To Run the configuration from Javac add the following dependency to the class path:
<dependency>
<groupId>com.prosyst.mbs.osgi</groupId>
<artifactId>com.prosyst.mbs.osgi.metatype.apt</artifactId>
<version>1.0.0</version>
</dependency>
From Maven
To use the Maven project generator:
<!-- that profile is if you want to use the Bosch metatype annotations -->
<!-- it is safe to remove it, if you don't plan to use the annotations -->
<profiles>
<profile>
<id>metatype-apt </id>
<activation>
<file>
<exists>metatype-apt </exists>
</file>
</activation>
<dependencies>
<dependency>
<groupId>com.prosyst.mbs.osgi </groupId>
<artifactId>com.prosyst.mbs.osgi.metatype.apt </artifactId>
<version>1.1.0 </version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins </groupId>
<artifactId>maven-compiler-plugin </artifactId>
<configuration>
<generatedSourcesDirectory>${project.build.directory}/classes </generatedSourcesDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix </groupId>
<artifactId>maven-bundle-plugin </artifactId>
<configuration>
<instructions>
<Include-Resource>{maven-resources},OSGI-INF=${project.build.directory}/classes/OSGI-INF </Include-Resource>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
From Eclipse
If imported Maven Projects are used then no additional configuration is required. For plain Java projects configure the Annotation Processing path of the compiler.
Loading Configurations
The new metatype is completely decoupled from the Configuration Admin service therefore is not possible to load the configuration properties.