Custom OSGi settings in Liferay 7.2

Custom OSGi settings implementation

Overview

This tutorial show how to implement configurable OSGi settings for your project.

OSGi module implementation

Problem formulation

Let's say, you need an account configuration for external system access with values:
  • "LifeDev User" - user name;
  • "LifeDev Password" - password.
And you need it to be displayed under custom category in System Settings.

Module Creation

Create module with the following structure:
images/01-module-structure.png
  • LifeDevConfigurationCategory - settings category;
  • LifeDevAccountConfiguration - OSGi settings;
  • LifeDevConfigurationKeys - constants;
  • Language.properties - resource bundle.

Dependencies

The list of dependencies in build.gradle:
dependencies {
    compileOnly group: "biz.aQute.bnd", name: "biz.aQute.bndlib", version: "3.1.0"
    compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "4.0.0"
    compileOnly group: "com.liferay.portal", name: "com.liferay.util.taglib", version: "2.0.0"
    compileOnly group: "com.liferay", name: "com.liferay.portal.configuration.metatype.api", version: "1.1.8"
    compileOnly group: "javax.portlet", name: "portlet-api", version: "3.0.0"
    compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1"
    compileOnly group: "jstl", name: "jstl", version: "1.2"
    compileOnly group: "org.osgi", name: "osgi.cmpn", version: "6.0.0"
    compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0"
    compileOnly group: "com.liferay", name: "com.liferay.configuration.admin.api", version: "2.1.3"
}

Bundle Descriptor Configuration

Here is a sample of bnd.bnd file:
Bundle-Name: LifeDev OSGi Configuration
Bundle-SymbolicName: com.lifedev.osgi.configuration
Liferay-Releng-Module-Group-Description: LifeDev OSGi Configuration Sample
Liferay-Releng-Module-Group-Title: LifeDev
Bundle-Version: 1.0.0
Web-ContextPath: /lifedev-osgi-configuration
Provide-Capability: \
    liferay.resource.bundle;\
        resource.bundle.base.name="content.Language",\
    liferay.resource.bundle;\
        bundle.symbolic.name=com.liferay.configuration.admin.web;\
        resource.bundle.aggregate:String="(bundle.symbolic.name=com.lifedev.osgi.configuration),(bundle.symbolic.name=com.liferay.configuration.admin.web)";\
        resource.bundle.base.name="content.Language";\
        service.ranking:Long="2";\
        servlet.context.name=com.liferay.configuration.admin.web
Export-Package: \
    com.lifedev.osgi.configuration,\
    com.lifedev.osgi.constants
-plugin.bundle: com.liferay.ant.bnd.resource.bundle.ResourceBundleLoaderAnalyzerPlugin
Key points here:
- merging custom resource bundle with com.liferay.configuration.admin.web
- exporting xxx.configuration and xxx.constants packages.

Custom category

LifeDevConfigurationCategory class for custom category creation:
@Component(service = ConfigurationCategory.class)
public class LifeDevConfigurationCategory implements ConfigurationCategory {

    @Override
    public String getCategoryKey() {
        return LifeDevConfigurationKeys.CATEGORY_KEY;
    }

    @Override
    public String getCategorySection() {
        return LifeDevConfigurationKeys.CATEGORY_SECTION;
    }

    @Override
    public String getCategoryIcon() {
        return LifeDevConfigurationKeys.CATEGORY_ICON;
    }

}
This will register custom category under specified section and with specified icon. 
Here are used the following values: 
LifeDevConfigurationKeys.CATEGORY_KEY = "lifedev-settings" - custom resource bundle key;
LifeDevConfigurationKeys.CATEGORY_SECTION = "platform" - this will register custom category under "Platform" section; 
LifeDevConfigurationKeys.CATEGORY_ICON = "forms" - this will display 'forms' icon for the category (may be defined any other one).

OSGi Settings

LifeDevAccountConfiguration interface for custom OSGi settings:
@ExtendedObjectClassDefinition(
        category = LifeDevConfigurationKeys.CATEGORY_KEY,
        scope = ExtendedObjectClassDefinition.Scope.SYSTEM
)
@Meta.OCD(
        id = LifeDevConfigurationKeys.ACCOUNT_CONFIGURATION_ID,
        localization = LifeDevConfigurationKeys.RESOURCE_BUNDLE,
        name = LifeDevConfigurationKeys.ACCOUNT_CONFIGURATION_NAME
)
public interface LifeDevAccountConfiguration {

    @Meta.AD(deflt = "life-dev", name = "lifedev-user", required = false)
    public String lifeDevUser();

    @Meta.AD(deflt = "1111", name = "lifedev-password", required = false)
    public String lifeDevPassword();

}
Here we define custom OSGi configuration settings in system scope (ExtendedObjectClassDefinition.Scope.SYSTEM), inside custom category (LifeDevConfigurationKeys.CATEGORY_KEY = "lifedev-settings") with lifeDevUserand lifeDevPassword fields.

Constants

LifeDevConfigurationKeys constants interface:
public interface LifeDevConfigurationKeys {

    String CATEGORY_ICON = "forms";

    String CATEGORY_SECTION = "platform";

    String CATEGORY_KEY = "lifedev-settings";

    String ACCOUNT_CONFIGURATION_ID = "com.lifedev.osgi.configuration.LifeDevAccountConfiguration";

    String ACCOUNT_CONFIGURATION_NAME = "lifedev-account-configuration";

    String RESOURCE_BUNDLE = "content/Language";

}

Resource Bundle

Language.properties file:
category.lifedev-settings=LifeDev Settings
lifedev-account-configuration=Account Configuration
lifedev-user=LifeDev User
lifedev-password=LifeDev Password
Note: for category resource bundle key category. prefix should be added (for lifedev-settings - category.lifedev-settings).

Deployment

Deploy created module.
If you're using Gradle workspace - check this issue.
Sample settings.gradle properties for Gradle workspace:
buildscript {
    dependencies {
        classpath group: "com.liferay", name: "com.liferay.gradle.plugins", version: "4.0.54"
        classpath group: "com.liferay", name: "com.liferay.gradle.plugins.workspace", version: "2.0.0"
        classpath group: "net.saliman", name: "gradle-properties-plugin", version: "1.4.6"
    }

    repositories {
        maven {
            url "https://repository-cdn.liferay.com/nexus/content/groups/public"
            url "https://plugins.gradle.org/m2/"
        }
    }
}

apply plugin: "net.saliman.properties"
apply plugin: "com.liferay.workspace"

Check Results

Go to "Control Panel -> Configuration -> System Settings", and check if new category had been added, sample:
images/02-category.png
Click on category, and check if OSGi settings are displayed:
images/03-settings.png
This should display predefined values by default. Now you can modify them and save, and then reference in your code.
Enjoy 😏

Comments

Popular posts from this blog

Liferay Search Container Example

Liferay DXP - max upload file size

Liferay Keycloak integration