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
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)
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;
}
}
/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.
Views
Replies
Total Likes
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
Hi, I have spent now 8 man days trying to get a config file read. It simply doesnt work in my env. I suspect its a bug in the latest cloud SDK. Which version of the SDK are you using? The code I have used here is simply the code from the github example, with nothing but a search and replace on the package names. It works perfectly, with the correct PID etc, except for the .cfg.json files dont work. i have tried other examples, and get the same problem. I have tried every possible conceivable variation and I have come to the conclusion its not the code, its something in the env, e.g. java 11, the latest cloud SDK, or something specific to M1 mac. I need to find a way to get round this issue, so thinking of creating a REST api to read config from some external DB.
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
You have so many problems with your code, can you try with below code set.
https://github.com/arunpatidar02/aemaacs-aemlab/commit/f66fbcf743d5ff043e2d41e6dde9a8d5d2d560d3
Views
Likes
Replies