How to Enable Configuration for OSGI Components with R6

Adding configuration to OSGi Component(s) is as simple as annotating your class with @Designate(ocd=””) annotation with the “ocd” property, and to make the @Activate method accepts an config param; as indicated below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// /com/sourcedcode/services/impl/MyserviceImpl.java
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.Designate;

@Component(service = MyService.class, immediate = true)
@Designate(ocd = SourcedCodeSiteSettingsConfig.class)
public class MyserviceImpl extends MyService {
    @Activate
    protected void activate(SourcedCodeSiteSettingsConfig config) {
        // do something
        // String name = config.name();
    }
}

The “ocd” property must be set with a configuration interface class that is annotated with @ObjectClassDefinition; the annotated interface class can be an imported Java interface class or inner Java interface class.

Once the @Designate annotation on the OSGI Component’s class and the @ObjectClassDefinition configuration interface are configured, the OSGI Component(s) will have enabled the configuration successfully; you should be able to find the configuration in the OSGI Apache Felix Console, under http://localhost:4502/system/console/configMgr.

Quick Links with Code Samples:
This article will highlight two different ways to enable configuration to your OSGI Component(s).

  1. Imported Class – Enable OSGI Component’s Configuration Implementation
  2. Inner Class – Enable OSGI Component’s Configuration Implementation

What is the @ObjectClassDefinition annotation?

The configuration interface is annotated with @ObjectClassDefinition where properties can be passed into the @ObjectClassDefinition annotation. The most common properties are @ObjectClassDefinition(name=””, description=””). The “name” property will be used as the title of the configuration popup within the OSGI Felix console, while the description property is used for the “description” of the popup.

1
2
3
4
5
6
7
8
9
10
11
12
13
// Example:
package com.sourcedcode.core.services;

import org.osgi.service.metatype.annotations.ObjectClassDefinition;

@ObjectClassDefinition(name = "SourcedCode - Site Settings Configuration",
    description = "dialog description"
)
public @interface SourcedCodeSiteSettingsConfigExample {    
    // config1 @AttributeDefinition()
    // config2 @AttributeDefinition()
    // config3 @AttributeDefinition()
}

What is the @AttributeDefinition annotation?

Declaration of the @AttributeDefinition annotations defines each configuration by identifying the type, the configuration reference name, config name and description.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.sourcedcode.core.services;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

@ObjectClassDefinition(name = "SourcedCode - Site Settings Configuration",
        description = "dialog description")
public @interface SourcedCodeSiteSettingsConfigExample {
    @AttributeDefinition(
            name = "String[] Label",
            description = "String[] Config Example Description",
            type = AttributeType.STRING)
    String[] config_string_array_example() default {"item1", "item2"};
    // config2 @AttributeDefinition()
    // config3 @AttributeDefinition()
}
Note!
To wrap your head around some of the essentials of @AttributeDefinition, checkout this blog article : OSGI R6 Configuration @AttributeDefinition Essentials Reference Guide.

1. Imported Class – Defining OSGI Component’s Configuration with Configuration Interface

The title of this section speaks for itself. The examples below "Step A" example provides sample code of a configuration interface class that is prepared to be imported OSGI Service Component, indicated in "Step B". This class have one responsibility, and its to provide the definition of the OSGI Component’s configuration interface.

Step A. Defining the annotated Configuration Interface

Isolated configuration interface class that prepared to be imported and referenced by the OSGI Service Component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.sourcedcode.core.services;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.osgi.service.metatype.annotations.Option;

@ObjectClassDefinition(name = "SourcedCode - Site Settings Configuration",
        description = "dialog description")
public @interface SourcedCodeSiteSettingsConfig {

    @AttributeDefinition(
            name = "String Label",
            description = "String Config Example Description",
            type = AttributeType.STRING)
    String config_string_example() default "Default String";

    @AttributeDefinition(
            name = "String[] Label",
            description = "String[] Config Example Description",
            type = AttributeType.STRING)
    String[] config_string_array_example() default {"item1", "item2"};

    @AttributeDefinition(
            name = "Long Label",
            description = "Long Config Example Description",
            type = AttributeType.LONG)
    long config_long_example() default 0L;

    @AttributeDefinition(
            name = "int Label",
            description = "innt Config Example Description",
            type = AttributeType.INTEGER)
    int config_number_example() default 0;

    @AttributeDefinition(
            name = "Short Label",
            description = "Short Config Example Description",
            type = AttributeType.SHORT)
    short config_short_example() default 0;

    @AttributeDefinition(
            name = "Char Label",
            description = "Char Config Example Description",
            type = AttributeType.CHARACTER)
    char config_char_example() default 0;

    @AttributeDefinition(
            name = "Byte Label",
            description = "Byte Config Example Description",
            type = AttributeType.BYTE)
    byte config_byte_example() default 0;

    @AttributeDefinition(
            name = "Double Label",
            description = "Double Config Example Description",
            type = AttributeType.DOUBLE)
    double config_double_example() default 0;

    @AttributeDefinition(
            name = "Float Label",
            description = "Float Config Example Description",
            type = AttributeType.FLOAT)
    float config_float_example() default 0;

    @AttributeDefinition(
            name = "Boolean Label",
            description = "Boolean Config Example Description",
            type = AttributeType.BOOLEAN)
    boolean config_boolean_example() default true;

    @AttributeDefinition(
            name = "Password Label",
            description = "Password Config Example Description",
            type = AttributeType.PASSWORD)
    String config_password_config_example() default "";

    @AttributeDefinition(
            name = "Dropdown Label",
            description = "Dropdown Config Example Description",
            options = {
                    @Option(label = "PRODUCTION", value = "PRODUCTION"),
                    @Option(label = "STAGING", value = "STAGING"),
                    @Option(label = "UAT", value = "UAT"),
                    @Option(label = "QA", value = "QA"),
                    @Option(label = "DEVELOP", value = "DEVELOP")
            }
    )
    String config_dropdown_example() default "DEVELOP";
}

Step B. Consuming the Configuration Interface by Imported Class

To use the configuration interface within our OSGI service component, we would need to annotation our service class with @Designate, with the ocd param pointing to the imported configuration interface class. Next, it would be as simple as setting up the initial @Activate method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.sourcedcode.core.services;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.Designate;
import com.sourcedcode.core.services.SourcedCodeSiteSettingsConfig;

@Component(service = SourcedCodeSiteSettingsService.class, immediate = true)
@Designate(ocd = SourcedCodeSiteSettingsConfig.class)
public class SourcedCodeSiteSettingsService {
    private String config_string_example;
    private String[] config_string_array_example;
    private long config_long_example;
    private int config_number_example;
    private short config_short_example;
    private char config_char_example;
    private byte config_byte_example;
    private double config_double_example;
    private float config_float_example;
    private Boolean config_boolean_example;
    private String config_password_getConfig_example;
    private String config_dropdown_example;

    @Activate
    protected void activate(SourcedCodeSiteSettingsConfig config) {
        this.config_string_example = config.config_string_example();
        this.config_string_array_example = config.config_string_array_example();
        this.config_long_example = config.config_long_example();
        this.config_number_example = config.config_number_example();
        this.config_short_example = config.config_short_example();
        this.config_char_example = config.config_char_example();
        this.config_byte_example = config.config_byte_example();
        this.config_double_example = config.config_double_example();
        this.config_float_example = config.config_float_example();
        this.config_boolean_example = config.config_boolean_example();
        this.config_password_getConfig_example = config.config_password_config_example();
        this.config_dropdown_example = config.config_dropdown_example();
    }
}
Outcome Explained:
The outcome of the OSGI Service and Configuration will result in an editable configuration within the OSGI Apache Felix Console.
OSGI Apache Felix Console - Active Dialog - Result of Enablement of OSGI Configuration

2. Inner Class – Defining OSGI Component’s Configuration with Configuration Interface

You can also define the annotated @ObjectClassDefinition interface as an inner class as shown below. To use the inner class configuration interface within our OSGI service, we would need to annotation our service class with @Designate, with the ocd param pointing to the inner interface class. Next, it would be as simple as setting up the initial @Activate method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.sourcedcode.core.services.impl;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.*;

@Component(service = SourcedCodeSiteSettingsServiceInlineExample.class, immediate = true)
@Designate(ocd = SourcedCodeSiteSettingsServiceInlineExample.SourcedCodeSiteSettingsConfig.class)
public class SourcedCodeSiteSettingsServiceInlineExample {

    @ObjectClassDefinition(name = "SourcedCode - Site Settings Configuration",
            description = "dialog description")
    protected @interface SourcedCodeSiteSettingsConfig {

        @AttributeDefinition(
                name = "String Label",
                description = "String Config Example Description",
                type = AttributeType.STRING)
        String config_string_example() default "Default String";

        @AttributeDefinition(
                name = "String[] Label",
                description = "String[] Config Example Description",
                type = AttributeType.STRING)
        String[] config_string_array_example() default {"item1", "item2"};

        @AttributeDefinition(
                name = "Long Label",
                description = "Long Config Example Description",
                type = AttributeType.LONG)
        long config_long_example() default 0L;
    }

    @Activate
    protected void activate(SourcedCodeSiteSettingsConfig config) {

    }
}

Thoughts…

I typically try my best to keep the configuration interface decoupled with OSGi components. This promotes better readability and maintainability. I would recommend you to stick with the Single Responsibility Principle; to separate concerns.

Note!
@AttributeDefinitions are the underlying formatting of how each OSGI configuration interaces are put together. If you wish to learn more about this topic, checkout this article: OSGI R6 Configuration @AttributeDefinition Essentials Reference Guide.

Hello, I am an enthusiastic Adobe Community Advisor and a seasoned Lead AEM Developer. I am currently serving as an AEM Technical Lead at MNPDigital.ca, bringing over a decade of extensive web engineering experience and more than eight years of practical AEM experience to the table. My goal is to give back to the AEM Full Stack Development community by sharing my wealth of knowledge with others. You can connect with me on LinkedIn.

2 thoughts on “How to Enable Configuration for OSGI Components with R6

  1. This is a really useful article. I am wondering is there any way to add two or more configuration in the same class using @Designate

Leave a Reply

Your email address will not be published. Required fields are marked *


Back To Top