New example of osgi config files not working with Aem cloud SDK. | Community
Skip to main content
Level 8
April 9, 2021

New example of osgi config files not working with Aem cloud SDK.

  • April 9, 2021
  • 3 replies
  • 4217 views

I tried and failed to get osgi config files to work in my own code as discussed here.

I found one example on the web of someone else who has created an OSGI config the same as mine, but unfortunately, they also don't include a config file.

I took their source code, added it to my project, added a config file, and get same result - AEM is ignoring the config file.

I suspect this is a problem with either

  • my env (M1 Mac running Java 11),
  • a bug in the latest AEM cloud SDK,
  • a problem with the wknd sample project.

Here is the example I took:

https://github.com/nateyolles/aem-osgi-annotation-demo

As this project wont build (AnnotationProcessor is not an ImageIO SPI class), I simply copied the following files to the same place in the wknd projectv (see below for exact source code)

  1. SampleOsgiService.java
  2. /impl/Configuration.java
  3. /impl/SampleOsgiServiceImpl.java
  4. SampleOsgiServlet.java

 

package com.adobe.aem.guides.wknd.core.services; public interface SampleOsgiService { String getSettings(); }package com.adobe.aem.guides.wknd.core.services.impl; import org.apache.commons.lang3.StringUtils; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.AttributeType; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.osgi.service.metatype.annotations.Option; @ObjectClassDefinition(name = "Annotation Demo Service - OSGi") public Configuration { @AttributeDefinition( name = "Boolean Property", description = "Sample boolean value", type = AttributeType.BOOLEAN ) boolean servicename_propertyname_boolean() default true; @AttributeDefinition( name = "String Property", description = "Sample String property", type = AttributeType.STRING ) String servicename_propertyname_string() default "foo"; @AttributeDefinition( name = "Dropdown property", description = "Sample dropdown property", options = { (label = "DAYS", value = "DAYS"), (label = "HOURS", value = "HOURS"), (label = "MILLISECONDS", value = "MILLISECONDS"), (label = "MINUTES", value = "MINUTES"), (label = "SECONDS", value = "SECONDS") } ) String servicename_propertyname_dropdown() default StringUtils.EMPTY; @AttributeDefinition( name = "String Array Property", description = "Sample String array property", type = AttributeType.STRING ) String[] servicename_propertyname_string_array() default {"foo", "bar"}; /* * To create password field, either set the AttributeType or have the * property name end with "*.password" (or both). */ @AttributeDefinition( name = "Password Property", description = "Sample password property", type = AttributeType.PASSWORD ) String servicename_propertyname_password() default StringUtils.EMPTY; @AttributeDefinition( name = "Long Property", description = "Sample long property", type = AttributeType.LONG ) long servicename_propertyname_long() default 0L; }

 

 

 

 

package com.adobe.aem.guides.wknd.core.services.impl; import org.apache.commons.lang3.ArrayUtils; import org.apache.sling.api.resource.ResourceResolverFactory; 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.Modified; import org.osgi.service.component.annotations.Reference; import org.osgi.service.metatype.annotations.Designate; import com.adobe.aem.guides.wknd.core.services.SampleOsgiService; @Component( immediate = true, service = SampleOsgiService.class, configurationPid = "com.adobe.aem.guides.wknd.core.services.impl.SampleOsgiServiceImpl" ) @Designate( ocd = Configuration.class ) public class SampleOsgiServiceImpl implements SampleOsgiService { private ResourceResolverFactory resolverFactory; boolean booleanProp; String stringProp; String dropdownProp; String[] stringArrayProp; char[] passwordProp; long longProp; public String getSettings() { StringBuilder sb = new StringBuilder(); sb.append("Sample OSGi Service:\n"); sb.append("booleanProp: " + booleanProp + "\n"); sb.append("stringProp: " + stringProp + "\n"); sb.append("dropdownProp: " + dropdownProp + "\n"); sb.append("stringArrayProp: " + ArrayUtils.toString(stringArrayProp) + "\n"); sb.append("passwordProp: " + String.valueOf(passwordProp) + "\n"); sb.append("longProp: " + longProp + "\n"); return sb.toString(); } protected final void activate(Configuration config) { booleanProp = config.servicename_propertyname_boolean(); stringProp = config.servicename_propertyname_string(); dropdownProp = config.servicename_propertyname_dropdown(); stringArrayProp = config.servicename_propertyname_string_array(); passwordProp = config.servicename_propertyname_password().toCharArray(); longProp = config.servicename_propertyname_long(); } protected void deactivate() { } }

 

 

package com.adobe.aem.guides.wknd.core.servlets; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet; import javax.servlet.ServletException; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.Designate; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import com.adobe.aem.guides.wknd.core.services.SampleOsgiService; @Component( immediate = true, service = Servlet.class, property = { "sling.servlet.extensions=txt", "sling.servlet.paths=/bin/osgi", "sling.servlet.paths=/bin/foo", "sling.servlet.methods=get" }, configurationPid = "com.adobe.aem.guides.wknd.core.servlets.SampleOsgiServlet" ) @Designate(ocd=SampleOsgiServlet.Configuration.class) public class SampleOsgiServlet extends SlingSafeMethodsServlet { private static final long serialVersionUID = 1L; private SampleOsgiService sampleOsgiService; private boolean enabled; protected void doGet(final SlingHttpServletRequest req, final SlingHttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); resp.setContentType("text/plain"); out.write("Annotation Demo Servlet - OSGi - enabled: " + enabled + "\n"); out.write(sampleOsgiService.getSettings()); } protected void Activate(Configuration config) { enabled = config.enabled(); } @ObjectClassDefinition(name = "Annotation Demo Servlet - OSGi") public Configuration { @AttributeDefinition( name = "Enable", description = "Sample boolean property" ) boolean enabled() default false; } }

 

I added a new conf file in 

 

/aem-guides-wknd/ui.config/src/main/content/jcr_root/apps/wknd/osgiconfig/config/com.adobe.aem.guides.wknd.core.services.impl.SampleOsgiServiceImpl.cfg.json

 

With the following content:

 

{ "servicename_propertyname_string":"bar", "servicename_propertyname_dropdown":"SECONDS" }

 

Then I deleted the crx dir, restarted the server, and did 

mvn clean install -PautoInstallSinglePackage.

However, when I run http://localhost:4502/bin/osgi I get:

 

Annotation Demo Servlet - OSGi - enabled: false Sample OSGi Service: booleanProp: true stringProp: foo dropdownProp: stringArrayProp: {foo,bar} passwordProp: longProp: 0

 

stringProp should be "bar" and dropdownProp should be "SECONDS"

Just like in my code, the ConfigMngr ends up with two copies of the config:

 The first one is created from the service, not from the .cfg.json file:

The second one, which I expected to contain my two values, only has "enable". Looking at the servlet, it also defines a configuration param, in addition to those created on the configuration class. This seems bizarre.

Below we see the config file is correct in crxde:

However, this config doesnt seem to exist in the configmgr. I would expect it to be called the same as the pid: com.adobe.aem.guides.wknd.core.services.impl.SampleOsgiServiceImpl.cfg.json but its not there.

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.

3 replies

Asutosh_Jena_
Community Advisor
Community Advisor
April 10, 2021

Hi @tb3dock 

 

After reading your questions below I just tried to create a sample OSGi service on my local SDK with .cfg.json as the extension for the OSGi configuration file and it works perfectly fine.

So I believe you are missing something while writing code. Please see the sample code below that I have written:

 

Service Interface which has only 3 attributes (2 string and 1 int type), with default value so incase, the configuration values are not provided in the respective runmode, the default values can be picked.

package com.adobe.aem.guides.wknd.core.services;

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

@ObjectClassDefinition(name = "EndPoint Configuration Service", description = "EndPoint Configuration Service")
public @interface EndPointConfigurationService {

@AttributeDefinition(name = "EndPoint URL", description = "Configure EndPoint URL", type = AttributeType.STRING)
String endPointURL() default "https://www.google.co.in";

@AttributeDefinition(name = "EndPoint Name", description = "Configure EndPoint Name", type = AttributeType.STRING)
String endPointName() default "Google India";

@AttributeDefinition(name = "EndPoint Name", description = "Configure EndPoint Name", type = AttributeType.INTEGER)
int timeoutDuration() default 10000;
}

Service Class Implementing the above Interface:

package com.adobe.aem.guides.wknd.core.services.impl;

import com.adobe.aem.guides.wknd.core.services.EndPointConfigurationService;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.Designate;

@Component(immediate = true, service = EndPointConfigurationServiceImpl.class,
property = {"process.label=EndPoint Configuration Service",
Constants.SERVICE_DESCRIPTION + "=EndPoint Configuration Service for XXXX Account",
Constants.SERVICE_VENDOR + "=Someone for Testing"})
@Designate(ocd = EndPointConfigurationService.class)
public class EndPointConfigurationServiceImpl {

private EndPointConfigurationService endPointConfigurationService;

@Activate
protected void activate(EndPointConfigurationService config) {
this.endPointConfigurationService = config;
}

public String getEndPointURL() {
return endPointConfigurationService.endPointURL();
}

public String getEndPointName() {
return endPointConfigurationService.endPointName();
}

public int getTimeoutDuration() {
return endPointConfigurationService.timeoutDuration();
}
}

OSGi Configuration that is added on default run mode in AEM:

com.adobe.aem.guides.wknd.core.services.impl.EndPointConfigurationServiceImpl.cfg.json

{
"endPointURL": "https://www.facebook.com",
"endPointName": "Facebook Global",
"timeoutDuration": "50000"
}

Sample Servlet to Invoke the Service:

As of now I have used a path based servlet, but it is preferred to use a Resource based servlet.

 

package com.adobe.aem.guides.wknd.core.servlets;

import com.adobe.aem.guides.wknd.core.services.impl.EndPointConfigurationServiceImpl;
import org.apache.http.entity.ContentType;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.ServletResolverConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;

@Component(service = Servlet.class, property = {"process.label=EndPoint Servlet",
Constants.SERVICE_DESCRIPTION + "=" + "This is a test servlet to get the end points from OSGi",
ServletResolverConstants.SLING_SERVLET_METHODS + "=" + HttpConstants.METHOD_GET,
ServletResolverConstants.SLING_SERVLET_PATHS + "=" + "/bin/testendpoint"})
public class EndPointServlet extends SlingSafeMethodsServlet {

private static final long serialVersionUID = 1L;

private static final Logger log = LoggerFactory.getLogger(EndPointServlet.class);

@Reference
private transient EndPointConfigurationServiceImpl endPointConfigurationService;

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
log.info("***** :: doGet :: Start :: *****");

response.setContentType(ContentType.TEXT_PLAIN.getMimeType());

final String responseString = "EndPointURL -> " + endPointConfigurationService.getEndPointURL() + "\n" +
"EndPointName -> " + endPointConfigurationService.getEndPointName() + "\n" +
"TimeOut Duration -> " + endPointConfigurationService.getTimeoutDuration();

log.info("***** :: doGet :: End :: *****");

response.getWriter().write(responseString);
}
}

 

Response when the config file is present: 

 

EndPointURL -> https://www.facebook.com
EndPointName -> Facebook Global
TimeOut Duration -> 50000 

 

Response when the config is not present, taking the default value from service:

EndPointURL -> https://www.google.co.in
EndPointName -> Google India
TimeOut Duration -> 10000

 

 

Hope this helps!

Thanks

TB3dockAuthor
Level 8
April 10, 2021
Looking at the example you kindly provided, its very different from every other service implementation i have found. In the others, the service interface defines service methods, not the AttributeDefinitions. A service should expose its services, not intrnal cong attributes which are not exposed outside the service?
joerghoh
Adobe Employee
Adobe Employee
April 10, 2021

First, you don't have "2 copies of the config", they are different ones (check the names and also the PIDs).

 

The OSGI configuration of the Servlet looks correct, because the configuration has just the definition for the enabled boolean property, I don't understand why you consider it as problematic. The default value of the configuration is displayed, because you haven't provided a actual configuration for it.

 

For the service: The "_" in the java names are escaping a "." in the actual property name. Which is a kind of workaround, because at the time when this type of annotations were introduced, a lot of osgi configurations were already out there which were using the "." as separator in the OSGI config names. And the SCR implementation before did not have the annotation and the config classes, there you had to read and convert the properties manually, and for this the API was using plain strings.

 

Please try and use this format as configuration:

{ "servicename.propertyname.string":"bar", "servicename.propertyname.dropdown":"SECONDS" }

 

I would recommend to use plain Camel Case namings also for the properties, that makes it much more readable, and use "_" only for legacy implementations which are using property names containing dots. So if you change your property names in the configuration to "servicenamePropertyNameDropDown" (or something better), you can use "servicenamePropertyNameDropDown" also in the OSGI configuration.

 

HTH,

Jörg

 

 

 

arunpatidar
Community Advisor
Community Advisor
April 11, 2021

You have so many problems with your code, can you try with below code set.

https://github.com/arunpatidar02/aemaacs-aemlab/commit/f66fbcf743d5ff043e2d41e6dde9a8d5d2d560d3

Arun Patidar