May 26, 2020
Estimated Post Reading Time ~

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 other 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 TestService with a dummy method named 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 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 has a unique value for each and every service implementation. This property could be anything you want to add. For example, I am using a 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 the 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 the 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 the 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


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.