3

I'm a complete newb at this so I apologize in advance. I'm trying to create an OSGi component that simply shows a hello world message and is configurable via the input from felix. Then spits it out on a jsp page. I'm using scr annotations to help do this. Here is my java code

package com.training.cq5.trainingApp;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.component.ComponentContext;
import org.apache.sling.commons.osgi.PropertiesUtil;

@Component(label= "Welcome Message",
        description = "Welcome Message for the training excercise",
        immediate = true, enabled = true, metatype=true)
@Properties({
    @Property(name = "welcome.message", value = "WelcomeMessage")
})
@Service(WelcomeMessage.class)
public class WelcomeMessage {

    private static String welcome_message = "Welcome";

    @Activate
    protected void activate(ComponentContext ctx) {
        welcome_message = PropertiesUtil.toString(ctx.getProperties().get(welcome_message), welcome_message);
    }

    public static String getMessage() { 
        return welcome_message;
    }
}

Here is were I am calling it in the JSP:

<%@ page import="com.training.cq5.trainingApp.WelcomeMessage" %>

<h2><%= WelcomeMessage.getMessage() %></h2>

Is there any reason why it's not updating from felix? All I'm getting is the "Welcome" text from the welcome_message string.

ilikeorangutans
  • 1,753
  • 1
  • 11
  • 14
Delmon Young
  • 2,013
  • 5
  • 39
  • 51

3 Answers3

6

You are accessing WelcomeMessage.getMessage() as a static method, but what you want is the actual service. When you annotate a class with the @Service and @Component annotation, you indicate to the OSGI framework that you want an instance of this class registered as a service. This service instance is managed by the OSGI framework, in terms of its lifecycle (when its instantiated) or through which classloader the appropriate classes are loaded.

However in order to use the @Component and @Service annotations, you'll have to use the Apache Felix SCR plugin. Once that works, your service will be instantiated.

Then you'll have to access the service. The easiest way in Sling, which you appear to be using, is SlingScriptHelper.getService() which lets you lookup a service.

Update

In OSGI services are registered by their type. When you declare a service with @Service(MyClass.class), the service will be registered under the type MyClass. To retrieve it you would query the service registry for a service of the given type. In Java code you'd be using either getServiceReference(Class clazz)/getService(ServiceReference reference) the @Reference annotation.

In a JSP on a Sling system you can use the SlingScriptHelper, as outlined earlier. Here's a short code sample (assuming correct imports):

<%
SlingBindings bindings = (SlingBindings) req.getAttribute(SlingBindings.class.getName());
SlingScriptHelper scriptHelper = bindings.getSling();
MyService service = scriptHelper.getService(MyService.class);
// ... do stuff with service.
%>

If you are going to work more with OSGI, I highly recommend the OSGI specification. It's free to download and explains everything in great detail.

Thom
  • 14,013
  • 25
  • 105
  • 185
ilikeorangutans
  • 1,753
  • 1
  • 11
  • 14
  • Thanks @ilikeorangutans. I do have the Apache Felix SCR plugin installed and working. So then my problem just lies in accessing it via sling? Sorry I'm a complete and I mean complete newb here. Any modifications to my code would be greatly appreciated. Or any code samples would help greatly. Thanks! – Delmon Young Apr 03 '13 at 12:51
  • Thanks @ilikeorangutans. Any idea why I'm getting this error when I add in your JSP. **SlingBindings cannot be resolved to a type** – Delmon Young Apr 04 '13 at 13:13
  • You're missing the appropriate import in your page: <%@page import="org.apache.sling.api.scripting.SlingBindings" %> – ilikeorangutans Apr 04 '13 at 16:19
  • Thanks @ilikeorangutans but for some reason now I'm getting a different error **Duplicate local variable bindings** any ideas? Thanks for the help I'm really new to this and still learning – Delmon Young Apr 06 '13 at 03:29
  • That means that bindings is already defined. You can probably just skip the first line. – ilikeorangutans Apr 10 '13 at 18:13
2

ilikeorangutans is correct that you don't want a static method on your OSGi service - the idea is that a service implements an interface, clients retrieve it from their OSGi context and use it via its service interface.

The Apache Sling webloader sample uses this technique to access a Webloader service in its request processing scripts. The scripts are ESP in this case (server-side javascript) but the principle is exactly the same with JSP.

The service interface is defined in Webloader.java, and WebLoaderImpl.java implements it as an OSGi service.

Then, the html.esp script gets the service using sling.getService:

var loader = sling.getService(Packages.org.apache.sling.samples.webloader.Webloader);
Bertrand Delacretaz
  • 6,100
  • 19
  • 24
  • Thanks @bertrand! The concept makes sense, but I'm a bit confused. I don't see an esp script in the webloader sample. But in the esp I'm assuming you use sling.getService and then just call loader.getMessage() in my case. Sorry bit of a newb here, is that all I would have to do in my jsp file to get it to work or does my java code need some modifications. Any modification to my code would be greatly appreciated. Thanks for the help! – Delmon Young Apr 03 '13 at 12:48
  • In the meantime I found an example in a Sling test script at http://svn.apache.org/repos/asf/sling/trunk/launchpad/integration-tests/src/main/resources/integration-test/serverscripts/jsp-engine-setup.jsp - you can have a look at how that uses the ConfigurationAdmin service and do something similar with your WelcomeService. You'll need to create a java interface that describes that service's contract, and create an implementation as done with the Webloader and WebLoaderImpl that I mentioned earlier. – Bertrand Delacretaz Apr 03 '13 at 16:59
0

Change this line:- welcome_message = PropertiesUtil.toString(ctx.getProperties().get(welcome_message), welcome_message);

to welcome_message = PropertiesUtil.toString(ctx.getProperties().get("welcome.message"), welcome_message);

notice the difference :-ctx.getProperties().get(welcome_message) vs ctx.getProperties().get("welcome.message")

Varun
  • 89
  • 6