OSGi component lifecycle

Learn about OSGi component lifecycle, including how to bind an OSGi service to the:

  • Activate
  • Modified
  • and Deactivate

…lifecycle events.

Transcript
Let’s take a look at how we can tie our activities OSGI service into the OSGI component life cycle. So OSGI components and the services are subject to three main lifecycle events within AEM.
The first is activate, and this is when the OSGI services first started. Second is modified, and this is triggered whenever an OSGI configuration for a service or component is changed and lastly, deactivate, and this is when the OSGI service is stopped or unregistered in AEM. So first let’s take a look at how we can tie into the activate life cycle event, as this is the most popular hook and the reason for this is OSGI services and components will often want to initialize some sort of internal state when they first start up and this often includes reading in, processing, and setting configuration properties that the OSGI component or service needs in order to execute properly. So all we need to do to hook into the activate life cycle is to create a new method, so we’ll make this a protected void method. We’ll call it activate. However, this can be called anything and the important piece is, we need to annotate it with the activate annotation. So this annotation is going to tell the OSGI container that whenever this OSGI service or component starts, that this method needs to be invoked. We’ll keep it simple by not passing in any parameters, but you can actually pass in a number of parameters such as the OSGI bundle contexts, the OSGI component context, or OSGI configuration properties, but for now, let’s keep it simple and we’ll use our activate method to set our list of activities here.
So let’s move this out into the activate method and just so we can see that this changed, let’s go ahead and change a couple of these activities and since it’s technically not a constant, let’s go ahead and just rename this and before we try our cut out, let’s do one more thing. Let’s put a log statement in our activate method so we can see that it’s invoked, as well as how many times it’s invoked. So for this, I’ll simply add a logger and down here, we can log a statement, printing out our activities that we’ve initialized.
Do you remember that OSGI services and components are singletons? So this activate method will be called once when this OSGI service starts, it will set this Singleton class field activities to the array, running, cycling, and skateboarding, and then all consumers of the service will be able to leverage and use that list of activities.
So let’s go ahead and deploy this and try this out.
So here on the left, we have our test harness webpage running in AEM, and I’ve pulled up the logs over here on the right and we’ll just grab four of the intended examples. So I’ll start by telling some logs. We can see a little bit of log information stating that we just installed our application. I’ll go ahead and clear these, and you can see over here on the left that we still have the old list. All right, we have skiing listed as a result. So what I’m going to do is I’m going to refresh this page, which will invoke our activity service, and then called get random activity and it should pull from the list of our new activities that we’re setting in our activate method and one thing that I want you to pay attention to is over here on the right, we should only see activate get called once, even though I’m going to be tapping on the refresh button multiple times, since our activity service will only be activated once upon first request of views. So let’s go ahead and see if when I tap refresh, we have a activate log method and we start seeing our new activity values.
So there you go, we can see our log statement here. So upon this first invocation, our activity services get random activity. AEM realized that our activity service had not been, had not been started or activated yet, since we had just re-installed that OSGI bundle and went ahead and activated that for us. So on subsequent refreshes, we should not see any more logging here because this OSGI service has already been started. So let’s go ahead and see if that it holds true.
So it looks like it’s working, we are getting more results. However, we’re not seeing any more log messages and that’s indicating that the activate method was called once when our OSGI service first started. Let’s head back to our code. You can see that it’s simple to hook into other events as well. So for instance, if we wanted to hook into the deactivate OSGI event, we can again create a method and make sure to annotate it with the deactivate annotation.
The third life cycle event is that modified event, which is triggered whenever an OSGI configuration changes. Quite often, if this is necessary, you’ll see the activate method modified with both activate aid, as well as modified, since typically the logic in activate needs to be rerun when new OSGI configurations are present. One last piece of advice to make sure that you keep your methods fast, that you’ve annotated with activate, modified, or deactivate, the reason is if these methods are slow, they can impact AEM’s overall management of other OSGI services that may depend on this, causing those services to be slow to start, so make sure you keep them fast, but we’ll take a closer look at this when we get into how we can provide OSGI configurations to our OSGI service. All right, I hope this helped you understand a little bit more on how you can tie your OSGI service into the OSGI component life cycle. -

Resources

Code

ActivitiesImpl.java

/core/src/main/java/com/adobe/aem/wknd/examples/core/adventures/impl/ActivitiesImpl.java

package com.adobe.aem.wknd.examples.core.adventures.impl;

import java.util.Random;

import com.adobe.aem.wknd.examples.core.adventures.Activities;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(
    service = { Activities.class }
)
public class ActivitiesImpl implements Activities {
    private static final Logger log = LoggerFactory.getLogger(ActivitiesImpl.class);

    private String[] activities;

    private final Random random = new Random();

    /**
     * @return the name of a random WKND adventure activity
     */
    public String getRandomActivity() {
        int randomIndex = random.nextInt(activities.length);
        return activities[randomIndex];
    }

    @Activate
    protected void activate() {
        this.activities = new String[] {
            "Running", "Cycling",  "Skateboarding"
        };

        log.info("Activated ActivitiesImpl with activities [ {} ]", String.join(", ", this.activities));
    }

    @Deactivate
    protected void deactivate() {
        log.info("ActivitiesImpl has been deactivated!");
    }
}
recommendation-more-help
4859a77c-7971-4ac9-8f5c-4260823c6f69