0

I am trying to create a very basic sling service in AEM:

package com.mypackage;

/**
 * A simple service interface
 */
public interface TestService {

    /**
     * @return the name of the underlying JCR repository implementation
     */
    public String getPropertyName();

}

The implementation class:

package com.mymypackage.impl;

import javax.jcr.Repository;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.jcr.api.SlingRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mypackage.TestService;


@Component(label = "Title", description = "Description.", immediate = true, metatype = true, policy = ConfigurationPolicy.REQUIRE)
@Service(value = {TestService.class})
@Properties({
    @Property(name = "propertyPath", label = "Property Label", description = "Property Desc.")
})
public class TestServiceImpl implements TestService {

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

    String propertyPath = null;

    @Activate
    public void activate(ComponentContext ctx) {
        Dictionary properties = ctx.getProperties();
        String propertyPath =(String)properties.get("propertyPath");
        log.info("====================getPropertyName activate========================"+propertyPath);
        this.propertyPath = propertyPath;
    }


    @Override
    public String getPropertyName() {
        // TODO Auto-generated method stub
        log.info("====================getPropertyName========================"+propertyPath);
        return propertyPath;
    }
}

and I have created a node of type sling:OsgiConfig inside the config folder. The name of this node is com.mypackage.impl.TestServiceImpl.xml and are the content of it:

<?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"
    propertyPath="http://www.myuhc.com"/>

and this is how I am trying to use it inside a Java class:

public static String getTestService() {
        TestService testService = new TestServiceImpl();
        String prop = testService.getPropertyName();
        return prop;
}

This method is being called from a JSP using customtaglib (method being mapped through a .tld file)

When I use this approach the activate method inside the HelloServiceImpl class is not called and hence the property is not set. But when I use the service inside a component JSP like this:

<%@page import="org.osgi.service.cm.ConfigurationAdmin"%>
<%@page import="org.osgi.service.cm.Configuration"%>

<%
Configuration conf = sling.getService(org.osgi.service.cm.ConfigurationAdmin.class).getConfiguration("Name of the config");
String myProp = (String) conf.getProperties().get("property key");
%>

everything works fine. There is something really wrong I must be doing while trying to call the service from a Java class. How can I use that approach. I don't want to use scriptlet inside JSP. Also, any best practices would be highly appreciated.

Thanks in advance

JE Bailey
  • 727
  • 7
  • 25
user972418
  • 817
  • 3
  • 25
  • 58
  • I dont find any issues running your code. However make sure the corresponding packages are exported / imported in your bnd files and check if the service is available in Felix console. – rakhi4110 Feb 12 '15 at 05:18
  • Hey Thanks for your response. I just edited my question. Could you please have a look at that. Thanks again. – user972418 Feb 12 '15 at 16:31
  • Are you getting any error messages when you use it inside Java? Make sure you are exporting your packages (Export-Package manifest header) so other bundles can see them (as per rakhi4110's suggestion). – Woodifer Feb 12 '15 at 23:46
  • There is no error. I put log messages inside the activate message but no logs were recorded. That led me to conclude that activate method is not getting called. Also, coming back to Export-package manifest header. Where do I need to provide it ? I am just doing the build in eclipse and haven't created any OSGi bundle exclusively for this service. Do you mean the project bundle ? – user972418 Feb 13 '15 at 00:45

3 Answers3

2

OSGi Services work within a life cycle which manages the creation and deletion of the Service instances.

As part of the container management of these instances, when the container creates the instance it calls the activation method with the appropriate values. So that the property can be assigned.

What you are doing in your first code snippet:

TestService testService = new TestServiceImpl();
String prop = testService.getPropertyName();

Is not using the containers version of your component. Your using the direct implementation and bypassing the container management.

To use the instance that is managed by the container. You need to request it from the container.

Which is exactly what your second snippet shows

sling.getService(org.osgi.service.cm.ConfigurationAdmin.class)

Is requesting the best matching service from the container.

To access a service from the container. You either need to be a Service yourself. Which you can do by the @Reference annotation.

You mentioned however being in a taglib which makes things a bit more complicated. You need to obtain a reference to the SlingScriptHelper which can be obtained from the pageContext like this;

    ServletRequest request = pageContext.getRequest();
    final SlingBindings bindings = (SlingBindings) request
            .getAttribute(SlingBindings.class.getName());
    final SlingScriptHelper scriptHelper = bindings.getSling();
    TestService service= scriptHelper
            .getService(com.mymypackage.impl.TestService.class);
JE Bailey
  • 727
  • 7
  • 25
0

The problem is, that sometimes when you try to re-install a bundle, some old compiled classess are not removed and replaced with a new one. Try to remove the /var/classes and/or /var/clientlibs nodes and re-install your projects.

kmb
  • 871
  • 5
  • 17
  • 34
  • Hey Thanks for your response. I just edited my question. Could you please have a look at that. Thanks again. – user972418 Feb 12 '15 at 16:32
  • 1
    If you want to use a service inside a Java Class, you need to get a reference to it. It can be done using @Reference annotation. It should be a field in your Java class: @Reference(policy=ReferencePolicy.DYNAMIC, cardinality=ReferenceCardinality.MANDATORY_UNARY) private TestService testService; Take a look at: http://felix.apache.org/documentation/subprojects/apache-felix-maven-scr-plugin/scr-annotations.html#reference – kmb Feb 13 '15 at 10:27
0

This may also be useful, if you are unable to use @Reference annotation for injecting your service

// get the TestServiceImpl.java service component
TestServiceImpl testService = getSlingScriptHelper().getService(TestServiceImpl.class);

//com.adobe.cq.sightly.WCMUsePojo.getSlingScriptHelper()