OSGi Components – Simply Simple – Part III

In the previous two parts (Part I and Part II) you learned how to use Declarative Services to develop your own components and services for OSGi. The topics included:

  • Creating components
  • Component lifecycle
  • Component configuration
  • Using services through references
  • Providing services

In this part we’ll cover another interesting topic:

Metatype Generation

The metatype specification (OSGi Compendium Chapter 105) provides a way to describe the configuration for a component. In general an OSGi configuration is just a dictionary with arbitrary key-value pairs. By defining a metatype description for the configuration, the developer of a component can define which properties together with their type the component expects. Such a metatype information can be used at runtime to generate forms to edit/create the configuration of a component. For example the Apache Felix Web Console does exactly that.

Now if you look at Part II of this series, if a component is configurable it contains already a component annotation for its properties:

public @interface MyComponentConfig {
     
    String welcome_message() default "Hello World!";
 
    int welcome_count() default 3;
 
    boolean output_goodbye() default true;
}

The above annotation already defines all possible properties together with their default values. Therefore the only thing you have to do is provide some human readable information like a label and a description for both, the configuration as a whole and each property. This can be done with some annotations from the metatype specification:

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

@ObjectClassDefinition(name = "Hello World Configuration",
		description = "The configuration for the hello world component.")
public @interface MyComponentConfig {
     
    @AttributeDefinition(name="Welcome Message", description="This message is displayed on startup of the component.")
    String welcome_message() default "Hello World!";
 
    @AttributeDefinition(name="Welcome Message Count", description="This is the number of times, the welcome message will be displayed. " +
                              "If less than one, no message will be displayed.")
    int welcome_count() default 3;
 
    @AttributeDefinition(name="Output Goodbye", description="Set this if the component should output a goodbye message.")
    boolean output_goodbye() default true;
}

The @ObjectClassDefinition annotation is used on the whole configuration annotation and for each attribute, the @AttributeDefinition annotation is used. With these annotations a metatype description for the MyComponentConfig class will be generated. However, we want to bind this configuration to our component which is a different class. Therefore you have to specify the @Designate annotation on your component class:

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

@Component
@Designate( ocd = MyComponentConfig.class )
public class MyFirstComponent {
 
    @Activate
    protected void activate( MyComponentConfig config ) {
    ...
}

And this will generate the metatype information for your component. It’s really easy to do such and it helps the user of your component to easily figure out how your component can be configured.