Sling Models with Sightly Part – IV (Key Annotations – II)

In this post, I will explain some important questions related to OSGi Services and Sling Models. These questions had been asked by some of my blog readers on the basis of my last blog.

So the Problem Statement is-

According to them, they have one interface with multiple service implementations and want to choose any one of these service implementations according to their need. So their questions were-

1. How to choose the desired service implementation from these service implementations in another services or servlets?
2. How to choose the desired service implementation from these service implementations in Sling Model Class?

I have created a demo implementation according to their requirement and for doing that I have created an interface named as TestService with a dummy method named as test(). Here is the code-

package services;
public interface TestService {
    void test();
}

Now, I have created two dummy service implementations of this interface. Here is the code for the first implementation named as TestServiceFirstImpl.

@Service
@Component(enabled = true,immediate = true,metatype = true)
public class TestServiceFirstImpl implements TestService {
    public void test() {
        System.out.println("inside first");
    }
}

Here is the code for my second implementation named as TestServiceSecondImpl.

@Service
@Component(enabled = true,immediate = true,metatype = true)
public class TestServiceSecondImpl  implements TestService {
    public void test() {
        System.out.println("inside second");
    }
}

Answer for the first question-
It is a two-step process. These steps are explained below-

Step 1
Add a new property that have a unique value for each and every service implementation. This property could be anything you want to add. For example, I am using service.label property for these services and on the basis of this property I will choose from these implementations.

Here are my new definitions for TestServiceFirstImpl class.

@Service
@Component(enabled = true,immediate = true,metatype = true)
@Property(name = "service.label", value = "first")
public class TestServiceFirstImpl implements TestService {
    public void test() {
        System.out.println("inside first");
    }
}

Code For TestServiceSecondImpl class.

@Service
@Component(enabled = true,immediate = true,metatype = true)
@Property(name = "service.label", value = "second")
public class TestServiceSecondImpl  implements TestService {

    public void test() {
        System.out.println("inside second");
    }
}

Step:- 2

Use @Reference annotation in another servlet or in OSGi Service with an extra attribute named as “target”. Just redefine this line as shown below-

@SlingServlet(paths="/bin/testService",extensions = "html",generateComponent = false)
@Component(enabled = true,immediate = true)
public class TestServlet extends SlingSafeMethodsServlet {

    @Reference(target = "(service.label=second)")
    TestService testService;

    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)throws ServletException, IOException{
        testService.test();
        response.getWriter().print(" CHECK YOUR LOGS ");
    }
}

Try to run your code, you will get the desired output.

Q2. How to choose these services in Sling Model class?

In Sling Model class you can call an external service using two annotations. These are-
1. @OSGiService
2. @Inject with @Source annotation

If you are using @OSGiService annotation then you have an attribute “filter”, here add your condition and you will get the desired implementation as shown below-

@OSGiService(filter = "(service.label=first)")
TestService testService;

If you are using @Inject with @Source annotation then you need to add one more annotation @Filter. Here is the new code-

    @Inject @Source("osgi-services")
    @Filter("(service.label=second)")
    TestService testService1;

Now here my complete working code that will show you the use of both of these two approaches.

@Model(adaptables = Resource.class)
public class ServiceResolver {


    @OSGiService(filter = "(service.label=first)")
    TestService testService;

    @Inject @Source("osgi-services")
    @Filter("(service.label=second)")
    TestService testService1;

    @PostConstruct
    public void activate(){
        System.out.println("Inside Post Constructor Method");
        testService.test();
        testService1.test();
    }

    @Inject
    @Default(values = "Ankur Chauhan")
    private String firstName;

    public String getFirstName() {
        return firstName;
    }
}
Q3. How am I testing these annotations in Sling Model class?

I have created a dummy component and that component calls these Sling Model classes. Sightly code snippet is-

<div data-sly-use.serviceResolver="sling.models.ServiceResolver">
   ${serviceResolver.firstName}
</div>

For complete working code, I am sharing the Git repository link.
https://bitbucket.org/accunitysoft/accunity-blog-snippets

Happy Coding..!!

Ankur Chauhan
Tech Lead

Sling Models with Sightly Part – II ( Key Points )

Sling Models with Sightly Part II

In this post, I will explain some key points, which need to be kept in mind while working with AEM, Sightly, and Sling Models.

Q1) Issues with Sling Models with Sightly while using AEM6.0 instance?

If you are using AEM6.0 then it provides org.apache.sling.models.api bundle with version 1.0.0 with very limited functionalities. e.g. You can inject some properties which exist on the resource and also you can use some basic annotations. See snippet example below:

@Model(adaptables=Resource.class)
public class SampleSlingModel {

    @Inject @Named("firstName")
    private String title;

    @PostConstruct
    private void calculateTotalMatches() {        
       System.out.println("Hi! " + title);
    }
}

But if you want to inject ResourceResolver or Resource object as shown below –

@Model(adaptables = Resource.class)
public class ResourceModel{

    @Inject @Default(values = "Ankur Chauhan")
    private String firstName;

    @Self
    private Resource resource;

    @Inject
    private ResourceResolver resourceResolver;

    @PostConstruct
    public void activate() {        
        System.out.println(resource);
    }
}

 

then this code will not run. Because Injectors for these kinds of Objects are not supported in Sling Model API version 1.0.0. In this case, you will get a warning that “not able to inject these properties” or you will get a null or NullPointerException.

Another point is “@Self” annotation will not work in AEM6.0. as its injector is also not available in Sling Model API version 1.0.0.

Q2) How to resolve this issue?

For resolving this issue just go to the maven repository and download the latest bundles for org.apache.sling.models.api and org.apache.sling.models.impl bundles.
Latest versions for these dependencies were 1.2.2 at the time of writing this blog.

Note :-  Both of these dependencies are mandatory.

Now you can install these bundles in two different ways.

1) Directly install these bundles using /system/console/bundles tab.

2) Place these bundles under /apps/<project>/install folder in your maven project so that whenever you build your project these bundles are automatically installed in your AEM instance.

Q3) Do I need these packages in AEM6.1?

AEM6.1 provides 1.1.0 version for these APIs, that support all annotations, but it’s always good to go with the latest APIs version. So I think you should keep these latest versions in your project for AEM6.1 instance. If you keep these JAR files in your project, you wont need to worry about the issue, that your code will run or not in any of the AEM6.x instances.

Q4) You are talking about AEM6.x versions, what about the older versions of CQ?

I am talking about these two versions because Sightly is only supported from AEM6.0 version but If you are working with CQ5.x version and want to use Sling Modes in your JSP files then you can follow the same steps by placing these API bundles into your maven project install directory and your code will work perfectly fine.

Q5) Where to find all Injectors information supported by any AEM instance?

You can check this information at-
http://<host>:<port>/system/console/status-slingmodels

I am also sharing the Git repository link.
Git repository link is –

https://bitbucket.org/argildx/accunity-blog-snippets

Happy Coding..!!

Ankur Chauhan
Tech Lead