Tag Archives: OSGi

The Truth about AEM Run Modes

The Adobe Experience Manager as a Cloud Service (AEM) is a very flexible platform. It allows (customer) developers to extend the two main services, author and publish via Java code. In many cases the exact same code needs to run on both services. However, there are use cases where the code should only run on one of them or behave differently. Similar, a different behaviour or configuration should be used in a development environment versus the production environment.

AEM provides the concept of run modes. A run mode indicates the type of the service as well as the environment type the service is running in. Therefore mutual exclusive run modes exists for author and publish as well as for dev, stage, and prod.

It is important to note that the concept of run modes is not a runtime concept. Following the twelve-factory methodology it has been designed as a deployment and provisioning concept. However, over time some bad pracices spread using run mode information at runtime to select different configurations or code paths.

Don’t Deploy Unused Code

If you want to run different code on author and publish, make the distinction through different deployments: deploy different code on author than on publish. This can be easily achieved by putting common code into a shared bundle and creating separate bundles for author or publish. Use a similar approach for components residing in the repository. This way you do not deploy unused or dead code.

It is bad practice to deploy the exact same code and then clutter the code with if statements checking for the run mode. The clean way is to just deploy what needs to run on a service.

Use Environment-Specific Configuration Values

It is a common use case to have different configuration values for different environments. For example when connecting to external services, different endpoints might be used for development than for production. For this create an OSGi configuration that uses placeholders:

{
  "service.endpoint": "$[env:EXTERNAL_SERVICE_URL]",
  "service.user":"$[env:EXTERNAL_SERVICE_USERNAME]",
  "service.password":"$[secret:EXTERNAL_SERVICE_PASSWORD]"
}

Use Service-Specific Configurations

Similar to environment-specific configuration values there are use cases where you want to have a different configuration for author than for publish. For this just create two OSGi configurations: one is bound to the author run mode, the other one is bound to the publish run mode.

This can also be combined with placeholders for having environment-specific values which also differ between author and publish.

Advanced Use Cases

Following the above three rules gives a clear separation and code. It avoids special casing within code which is over time hard to understand and maintain. Even more advanced use cases can be handled this way. For example if you want to have the same service on author and publish but with a different algorithm: Author is always using fresh data within a service, while the data is cached on publish within that service. In such case you might want to use a behavioural pattern like the strategy pattern. This goes back to the first rule. Create different code deployments for author and publish and then use the code through OSGi services from some common shared code base.

Use Run Modes for Deployment and Provisioning

In summary, it is good practice to leverage run modes for describing the deployment and provisioning. Define precisely which bundles and configurations apply to both, author and publish, as well as which of them only apply for one service.

Leverage environment-specific configuration values to provision different values for each environment type. But refrain from trying to deploy different code per environment type.

Guide on Using OSGi Configurations

Configuration Admin is amongst the most used services from the OSGi specification. But on the other hand, the usage is barely noticed. Component frameworks like Declarative Services (DS) or CDI Integration take care of the heavy lifting. Configuration Admin allows to create, update and delete configurations. It is up to the implementation where these configurations are stored. A configuration has a unique persistent identifier (PID) and a dictionary of properties. This guide explains how to best interact with Configuration Admin when writing OSGi code. It is based on over a decade of experience working on large enterprise applications using OSGi. It might not apply to every OSGi application.

Do not talk to Configuration Admin

The basic rule for dealing with OSGi configurations is very simply: do not write code that talks to Configuration Admin directly. But of course you should use OSGi configurations to configure your application. So how does that work? The answer is very easy: let someone else talk to Configuration Admin and do the work for you.

A very nice way to develop OSGi components and services is to use Declarative Services (DS). By using Java annotations, the component code tells DS which configuration(s) it wants to consume. DS does all the hard work behind the scenes. Defining a Component Property Type simplifies the usage further. A component property type provides type conversion and default values.

But if it is that easy why am I writing this? It is good to know some of the details about configuration handling – especially in cases where you cannot use DS.

Be Aware of Configuration Plugins

OSGi configurations are used to configure the whole system. In many cases that includes configurations for connections to other systems or services. Such configurations usually include endpoints and credentials. The values for these properties might depend on your environment: a different endpoint is used in development than in production. In addition, you don’t want to store credentials or any other secrets directly in your code or configuration.

A good mechanism for managing such configurations is to use “late binding” of the values. Instead of storing the values directly in the OSGi configuration you use placeholders. The placeholders get replaced at runtime with the real values. Support for such placeholders usually comes in the form of Configuration Plugins. The Apache Felix Interpolation Plugin is a very nice plugin supporting environment variables, system properties and secrets. For example, a configuration for a connection could look like this (using the Configurator JSON notation) :

{
  "de.osoco.business.server" : {
    "url" : "$[env:BUSINESS_SERVER_URL]",
    "user": "$[env:BUSINESS_SERVER_USER]",
    "password" : "$[secret:business.server.pw]"
  }
}

It uses environment variables for the url and the username and a secret for the password. With such an approach, the configuration stored in Configuration Admin only contains the above visible placeholders. However, when the configurations is provided to the code using the configuration, a plugin like the Apache Felix Interpolation Plugin needs to be invoked, replacing the placeholders with real values and then handing out the configuration.

The good news is, if you are using Declarative Services this happens automatically and you don’t have to worry about it.

ManagedService(Factory)

However, sometimes there are use cases where you either can’t or want to use Declarative Services (or a similar component framework). The second best way to deal with configurations is to register either a ManagedService or ManagedServiceFactory. These are basically callbacks which are called by Configuration Admin with the configurations, the registered service is interested in. And the good part is, Configuration Admin calls the configuration plugins before handing out the configuration.

Threefore it is advisable to either use Declarative Services or register a managed service for consuming OSGi configurations. But there might be some very rare use cases where both is not possible and you need to talk to Configuration Admin directly.

How to Talk to Configuration Admin

First, as explained, try to avoid this situation. If you can’t, be aware of the following points. If you want to get a configuration from Configuration Admin do not use one of the getter methods like getConfiguration or getFactoryConfiguration. These methods have side effects and will create such a configuration if it does not exist! Use listConfigurations instead:

ConfigurationAdmin ca = ...;
Configuration[] configs =  
      ca.listConfigurations("service.pid=de.osoco.business.server");
if ( configs != null && configs.length > 0 ) {
    // use configuration (we just assume we got only one configuration back)
    Configuration cfg = configs[0];
    ...
}

Once you have the configuration, the next thing is to get its properties – there is a method called getProperties on a Configuration object – but do you remember the placeholders and configuration plugins? If you call getProperties these are not invoked, and the values will be the placeholders itself! Therefore don’t use that method for consuming configurations – use getProcessedProperties instead. That method invokes all plugins before handing out the properties.

To identify the caller getProcessedProperties takes a required ServiceReference as a parameter. If you already have a reference at hand, use it – if not, you need to register a service in the service registry.

Avoid Configuration Binding

Finally, if you want to create configurations, the previously mentioned getter methods (getConfiguration and getFactoryConfiguration) can be used to do so. Make sure that you use the variant which takes the additional location parameter and pass in null for the location. If you don’t do this, then the configuration gets bound to your bundle and will not be delivered to other consumers anymore. Configuration binding and targeting is a complicated topic – which is best to avoid. Of course, as always, there are good use cases for these features. Only use it if you really need it. This article contains some information about configuration binding and DS.

I hope with these tips, handling OSGi configurations becomes very easy. Just as a recap:

  • Use component frameworks like Declarative Services – all hard work is done for you
  • If that’s not possible, use ManagedService or ManagedServiceFactory – again most of the hard work is done for you
  • If that’s also not possible, make sure to not create configurations as a side effect and use the right method to get properties
  • Avoid configuration binding and targeting if possible

OSGi Components – Simply Simple – Part I

There is a lot of prejudice and misunderstanding when it comes to OSGi. As with every technology there is a learning curve and some things might be different than you are used to. But change isn’t necessarily a bad thing.

Component-oriented development is a very common and powerful software engineering style where you assemble your application out of components. A component might offer a service, e.g. a scheduler service. Other components can use this scheduler service.

Or a little bit more formal: a component is a piece of software managed by a (component) container. In Java this means this is an instance, created and managed by a container. Therefore it is not the task of the developer to create or configure these instances. This is the task of the container. If the component uses other services, it is also the task of the container to pass these services to the component. Therefore a service is a component which provides one or more services. In Java this means a service implements one or more interfaces where an interface represents the service description or contract.

OSGi Components with Declarative Services

I will show that developing components with OSGi is really simple and straightforward with no additional cruft – and I think it can’t really get much easier than this. We’ll be using the Declarative Services specification(see OSGi Compendium Chapter 112) in it’s latest version (R6). With the use of the annotations also defined in this specification, components are usually POJOs with all its benefits.

I will not go into the usual tooling discussion – there are different tools out there for your favorite development environment for processing these annotations, like Ant, Maven, Gradle. In contrast to other solutions, all the annotations are build time annotations. They are processed by some tooling and create additional files which are put in the final jar (bundle). I don’t explain everything in every detail and leave out things here and there – it is advisable to read the mentioned specs in addition!

Please note, that using Declarative Services (DS) is one way of developing components and services for OSGi, there are other approaches like Blueprint, Apache Felix iPojo, Apache Felix Dependency Manager etc. Each one of these solutions (including DS) has pros in some areas while it has cons in others. I think, DS is a simple and straightforward way of developing components and its a standard maintained by the OSGi alliance. It’s easy to learn, easy to manage and maintain and provides all required features. However, if you plan to use something different than DS, the real good news is: you can mix and match all these approaches – they’re all based on the OSGi service registry and work well together!

With Declarative Services we have a nice component container managing our components and providing them with configurations and required services. As we’re talking about OSGi here, we’re talking about bundles, so the classes for your component or service go into a bundle. Declarative Services (DS) needs to know which classes are components, what services they might provide etc. Therefore your bundle should contain an XML file for DS which exactly defines this. You might know such XML configuration files from other frameworks – however, the DS format is rather simple and – the good part – you never have to write this by hand and never even have to look at it (ok, if things go wrong, it might sometimes help to check it). At runtime the SCR implementation will read these descriptor files and manage the components and services. Oh, I forgot to explain SCR 🙂 It stands for Service Component Runtime and can be seen as the container defined by DS. Now usually people use SCR and DS as synonyms though that is not quiet correct for the purists amongst us.

So let’s start…

Components

If you want to write a component which is managed by the container, just add the @Component annotation to your class:

package com.mycompany.cool.project.impl;

import org.osgi.service.component.annotations.Component;

@Component
public class MyFirstComponent { }

Build your project, deploy your bundle into an OSGi framework which has SCR running (I recommend the implementation from Apache Felix, version 2.0 or higher) – and your component will be instantiated by the container on bundle start. As a component has never public API but is a private implementation, the class should go into a private package which is not exported by the bundle! It is good style to add impl or similar somewhere in the package name, like com.mycompany.cool.project.impl.

Now, while this component runs and works – it’s not really useful as the component does nothing.

Lifecycle

As noted above, the container manages the lifecycle of the component, its instantiation and removal. In order to make this work, the component class needs the default zero argument constructor. However, if the component wants to do something during the creation or the deletion phase, it can implement an activate and/or deactivate method and mark it with the according annotation:

package com.mycompany.cool.project.impl;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Deactivate;
 
@Component
public class MyFirstComponent {
 
    @Activate
    protected void activate() {
        // do something
    }
 
    @Deactivate
    protected void deactivate() {
        // do something
    }
}

It is good practice to name these methods activate and deactivate – however you could pick any other name if you want. The methods have to be protected with no return value.

Still, we have a component not doing that much, so lets do something “more” usefull:

package com.mycompany.cool.project.impl;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
 
@Component
public class MyFirstComponent {
 
    private volatile boolean doRun;
 
    @Activate
    protected void activate() {
        final Thread t = new Thread() {
            public void run() {
                doIt();
            }
        };
        t.setDaemon(true);
        doRun = true;
        t.start();
    }
 
    private void doIt() {
        while (doRun) {
            System.out.println("I'm still alive!");
            try {
                Thread.sleep(60 * 1000);
            } catch (InterruptedException e) {}
        }
    }
 
    @Deactivate
    protected void deactivate() {
        doRun = false;
    }
}

We create a new thread in activate and start it – in the thread we print out a message every minute. In addition we use a boolean variable to stop the thread when the component gets deactivated. While this example is not a production ready implementation, it shows that the thread of the activate and deactivate method “belong” to the component container – so the component should return as quickly as possible and do not block this method. Therefore we created an own thread. Please note, that this is just an example to demonstrate something, for things like timed execution, you would rather use a scheduler invoking your component periodically instead of running an own thread inside your component. The Apache Sling scheduler is a great way of doing things like these.

Using Services

A single component alone does usually not make up an application – it is rather assembled of dozens if not hundreds of components interacting. And interaction happens by using services.
So let’s extend our example – we use the event admin (another OSGi compendium spec with a great implementation from the Apache Felix project). The event admin is a service which allows us to send out events in a publish/subscrib kind of way. So each event gets a topic, and subscribers subscribe with the topics they are interested in.

A component can use other services by using the @Reference annotation. The container uses dependency injection and injects references into fields:

package com.mycompany.cool.project.impl;
 
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
 
@Component
public class MyFirstComponent {
 
    @Reference
    private EventAdmin eventAdmin;
 
    private volatile boolean doRun;
 
    @Activate
    protected void activate() {
        final Thread t = new Thread() {
            public void run() {
                doIt();
            }
        };
        t.setDaemon(true);
        doRun = true;
        t.start();
    }
 
    private void doIt() {
        while (doRun) {
            final Event event = new Event("alive", null);
            this.eventAdmin.sendEvent(event);
            try {
                Thread.sleep(60 * 1000);
            } catch (InterruptedException e) {}
        }
    }
 
    @Deactivate
    protected void deactivate() {
        doRun = false;
    }
}

The above example looks pretty simple and from a developer’s point of view it is simple. You just declare an instance variable with the type of the service you want (services are registered by the interface(s) they implement) and add the @Reference annotation. Before the component is activated (the activate method is called), this instance field is set with the event admin service from the container. Therefore it is safe to assume that the event admin service is available and setup.

As OSGi is highly dynamic, bundles and services can come and go – so the event admin might be there or not, disappear, reappear etc. You don’t really have to care about this (at least not for the moment). Your component is only active if the event admin is available – if not, your component will either not be activated or will get deactivated. We’ll go deeper into references later on and learn how to cope with all the dynamics of services.

With just these four annotations you already know the building blocks for developing OSGi components and services. I suggest you test out the examples and make yourself familiar with using your favorite development environment. Once you are able to successfully build and deploy these components, you’re ready for the cool fun stuff of DS which I will show in part two.

Stay tuned.