Category Archives: AEM OSGI Config

AEM Solution: How to override third-party OSGI Config in AEM

Overview

An overriding concept is a pretty known subject in AEM. Components can be overridden in an application with sling resolution technique. Similarly, Apache sling has a resolution order to resolve OSGi configs as well. Basically, application specific config’s can override AEM Libs configs. For more details on OSGI config & their resolution order, Read my posts here.

Scenarios/Problems

Let’s consider a scenario of a project where you have to use another AEM Project or third-party source code like ACS Commons. And, There are some services which you want to use but with different configuration. Assume services do have configurations in place.

Now you might be thinking that what is the big deal in that. We can upload third-party code & change the configuration. Well, That is the whole point. The moment you change the configuration for your application, One more maintenance issue happens. Got it? No?

No worry. The issue is that every time you update/install third-party code for your application, You have to manually change the configuration. You might think it is okay. But it is not when you have to support the same in every environment after every deployment. Someone has to fix every time. And what if the configuration has to be updated in prod publish environment. It is tough to maintain. Let me explain with config files.

#Thirdparty config’s XML File match for ContentFeed service under config.publish folder & apps folder is /apps/abc/thirdparty/. ContentFeed Service is part of platform code base.

#Base config: com.abc.core.contentFeed.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="sling:OsgiConfig"
    contentFeedPath="https://example.com/api/core/platform"/>

#Your application would like to override this config. And apps is /apps/myapp etc.

#Brand specific config: com.abc.core.contentFeed.xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="sling:OsgiConfig"
    contentFeedPath="https://example.com/api/feed<myapp-feeds>"/>

Now, ContentFeed service does not pick your application-specific config & even though you have the same config in your application. It always picks up the third party config. And it happens ContentFeed service is part of platform source code.  I hope the problem is clear to you now. let’s see a solution.


General Solution

A general approach is to keep modifying third-party configs in every environment after each deployment. And, When QA reports this or that not working, a new person struggle to find why it is not working. Most of us do not remember that service configs are overridden by the deployment. The second approach is to override the full code itself with different service name & configurations. Must easy to maintain but having duplicate code & same bugs as third-party has. And fixing bugs every time something fixed in the third-party source.

Alternative Solution

Solution to above problem is simple. Make sure your app config file name is the same as third-party config. Read about XML config & service naming convention. AEM OSGi Config Resolution Order

To make sure Service picks your configuration, You need to create the same XML config under the same run mode folder & with additional run mode info because that is how AEM put precedence over other config’s. Let me explain with source code.

#Third-Party config file name is com.abc.core.contentFeed.xml
folder structure is: /apps/third-party/config.publish, config.author etc.

#Your app config name must be com.abc.core.contentFeed.xml
your Folder structure for config must be: /apps/third-party/config.publish.qa, /apps/third-party/config.publish.stage etc.

I hope the solution is clear to you. Solution seems easy but it solves general problem. Leave a comment if you have any question or feedback. thanks in advance.

AEM Solution: How to get OSGI Service object in POJO?

Overview

In AEM, OSGI Container supports dependency injection which means one OSGi service can be injected into another service using @Reference annotation. Dependency injection design is a well-known design pattern.   In this post, would like to explain what are the ways to get a reference of OSGi Service? 

Problems/Scenarios

As you know, In some case you are not able to get the object using @Reference annotation. Basically, OSGI container does not allow you to inject NON-OSGI classes (POJO) into another class. 

This happens when you have a class which is not registered as OSGI Component & Service. In such cases, You are left with the following option. Get the service object through a parameter to our class or get the service object through Sling request object. In Sightly model, referencing of services are possible now.

Solutions

Here is the example how to get service object through Sling request object.

// Fetching service reference from request object.
public class Example{
 public ServiceObject YouServiceReference(SlingHttpRequest request){
      final SlingBindings bindings = (SlingBindings) request.getAttribute(SlingBindings.class.getName());
      SlingScriptHelper slingScriptHelper = bindings.getSling();
     YouServiceReference service = slingScriptHelper.getService(YouServiceReference.class);
        return service
   }
}
#Wiht Sightly POJO
public class Example extends WCMUsePojo{
 public ServiceObject YouServiceReference(SlingHttpRequest request){
      return getSlingScriptHelper.getService(YouServiceReference.class);
   }
}

AEM Solution: AEM OSGi Config Resolution Order

Overview

In this post, will talk about simple concept what is OSGi (i.e open service gateway interface) resolution order & what does this order is different when AEM starts & when something we change from OSGi console.

OSGI Config Resolution Order: at Startup vs Runtime

AEM Apache Felix based OSGi runtime environment(aka system console) loads the configurations in two different ways and makes them available to the application. Read the section “How these configs are resolved?” in this post How AEM OSGi works?

The same OSGi Apache Felix framework loads configuration runtime different. The following order of precedence applies: 

  • If you have modified any config directly from system console (i.e AEM OSGi admin console) then AEM creates another .config file and this file gets precedence over your XML file, apps or libs.
  • If you have made changes in config file under apps and the same config has not been modified from system console then apps modified config would take the precedence over libs and will available to the application immediately.
  • If you have modified any config under libs & it is not overridden at the apps level & it is not modified from system console then modified config will take the precedence.

Config Resolution Order with multiple run modes:

For run mode specific configurations, multiple run modes can be combined. For example, you can create configuration folders in the following style:

/apps/*/config.<runmode1>.<runmode2>/

Configurations in such folders will be applied if all run modes match a run mode defined at startup. For example, if an instance was started with the run modes author,dev,emea, configuration nodes in /apps/*/config.emea/apps/*/config.author.dev/ and /apps/*/config.author.emea.dev/ will be applied, while configuration nodes in /apps/*/config.author.asean/ and /config/author.dev.emea.noldap/ will not be applied.

If multiple configurations for the same PID are applicable, the configuration with the highest number of matching run modes is applied.

For example, if an instance was started with the run modes author,dev,emea, and both /apps/*/config.author/ and /apps/*/config.emea.author/ define a configuration for
com.day.cq.wcm.core.impl.VersionManagerImpl, the configuration in/apps/*/config.emea.author/ will be applied.

This rule’s granularity is at a PID level. You cannot define some properties for the same PID in/apps/*/config.author/ and more specific ones in /apps/*/config.emea.author/ for the same PID.
The configuration with the highest number of matching run modes will be effective for the entire PID.

AEM Solution: How does an AEM OSGi Config work?

Overview

In this post, would like to explain to the readers about how does an OSGi (i.e Open service gateway interface) Config work? Would like to clarify some doubts in this post.

What is AEM OSGi Config?

AEM OSGi config is a mechanism to maintain configurations which are bound to change & varies based on different scenarios. Like loading same config file with QA, Stage & Prod with different entries. OSGi configs are available within the OSGi runtime environment so those can be used by any other service at any time with help of OSGi service registry model. 

How to use OSGi Configs?

To use OSGi Config in your OSGi based application like AEM (i.e Adobe experience manager). Just have an XML File & bind configuration entries (i.e XML file) with Java service or component registered in the OSGi framework.  Here is the AEM example. See a simple XML file  & relative OSGi service.

# OSGi XML File naming convention

com.osgiConfig.example.OsgiConfigExample.xml

#XML File Content in source code.

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="sling:OsgiConfig"
    servicePath="https://example.com/api/geolocation"/>
package com.osgiConfig.example;
@Service
@Component
public class OsgiConfigExample implements SlingSafeMethodsServlet {
   @Property(label = "service path",value = "exmple.com")
   private static final String SERVICE_PATH = "servicePath";
   public void doGet(SlingHttpServletRequest req, SlingHttpServletResponse res) 
   {// your code goes here ...}
}

How these configs are resolved?

The following order of precedence is used:

  • Repository nodes under /apps/*/config….either with type sling:OsgiConfig or property files.
  • Repository nodes with type sling:OsgiConfig under /libs/*/config…. (out-of-the-box definitions).
  • Any .config files from <cq-installation-dir>/crx-quickstart/launchpad/config/…. on the local file system.

Is Naming convention of XML File necessary?

Yes. Your xml file must follow name convention and that is package name & service class name where the properties annotations are.

Do you really need XML File in our source code?

Yes. OSGi config files must be maintained & put in run mode config folders in your source code. Like config, config.author, config.author.QA etc. If those are not maintained that way, you need to open OSGi config from OSGi admin console & change the config. It becomes more difficult when you have to do the same in the production environment.

Is it really need to have property annotation at the class level?

This question is important because most of us think that if we have OSGi config XML in run mode & it matches the service package name & class then required configuration would be available to use. However, that is not the case. Property annotation gets resolved when an OSGi service/component becomes active in OSGi runtime environment. And OSGi service resolves these properties at the service level. So if you do not have these properties at the service level then Service or component do not load OSGI config’s from your run mode.

Final Thought

Here I tried to put some of the questions & their answers. But still there could be some questions which are not listed here. You can post in comment & I will get back to you.